summaryrefslogtreecommitdiff
path: root/natsort/compat/fake_fastnumbers.py
blob: 71775519c9c404c6d37a5214622511260af4644b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# -*- coding: utf-8 -*-
"""
This module is intended to replicate some of the functionality
from the fastnumbers module in the event that module is not installed.
"""

# Std. lib imports.
import unicodedata

# Local imports.
from natsort.unicode_numbers import decimal_chars

NAN_INF = [
    "INF",
    "INf",
    "Inf",
    "inF",
    "iNF",
    "InF",
    "inf",
    "iNf",
    "NAN",
    "nan",
    "NaN",
    "nAn",
    "naN",
    "NAn",
    "nAN",
    "Nan",
]
NAN_INF.extend(["+" + x[:2] for x in NAN_INF] + ["-" + x[:2] for x in NAN_INF])
NAN_INF = frozenset(NAN_INF)
ASCII_NUMS = "0123456789+-"
POTENTIAL_FIRST_CHAR = frozenset(decimal_chars + list(ASCII_NUMS + "."))


# noinspection PyIncorrectDocstring
def fast_float(
    x,
    key=lambda x: x,
    nan=None,
    _uni=unicodedata.numeric,
    _nan_inf=NAN_INF,
    _first_char=POTENTIAL_FIRST_CHAR,
):
    """
    Convert a string to a float quickly, return input as-is if not possible.

    We don't need to accept all input that the real fast_int accepts because
    natsort is controlling what is passed to this function.

    Parameters
    ----------
    x : str
        String to attempt to convert to a float.
    key : callable
        Single-argument function to apply to *x* if conversion fails.
    nan : object
        Value to return instead of NaN if NaN would be returned.

    Returns
    -------
    *str* or *float*

    """
    if x[0] in _first_char or x.lstrip()[:3] in _nan_inf:
        try:
            x = float(x)
            return nan if nan is not None and x != x else x
        except ValueError:
            try:
                return _uni(x, key(x)) if len(x) == 1 else key(x)
            except TypeError:  # pragma: no cover
                return key(x)
    else:
        try:
            return _uni(x, key(x)) if len(x) == 1 else key(x)
        except TypeError:  # pragma: no cover
            return key(x)


# noinspection PyIncorrectDocstring
def fast_int(
    x, key=lambda x: x, _uni=unicodedata.digit, _first_char=POTENTIAL_FIRST_CHAR
):
    """
    Convert a string to a int quickly, return input as-is if not possible.

    We don't need to accept all input that the real fast_int accepts because
    natsort is controlling what is passed to this function.

    Parameters
    ----------
    x : str
        String to attempt to convert to an int.
    key : callable
        Single-argument function to apply to *x* if conversion fails.

    Returns
    -------
    *str* or *int*

    """
    if x[0] in _first_char:
        try:
            return int(x)
        except ValueError:
            try:
                return _uni(x, key(x)) if len(x) == 1 else key(x)
            except TypeError:  # pragma: no cover
                return key(x)
    else:
        try:
            return _uni(x, key(x)) if len(x) == 1 else key(x)
        except TypeError:  # pragma: no cover
            return key(x)