Skip to content

Commit

Permalink
Begin trying to simplify _isnumber
Browse files Browse the repository at this point in the history
  • Loading branch information
pjkundert committed Oct 8, 2024
1 parent c37de75 commit 232ed74
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,20 @@ data in the column is used to infer the type:

```

The deduced type (eg. str, float) influences the rendering of any types
that have alternative representations. For example, since `Fraction` has
methods `__str__` and `__float__` defined (and hence is convertible to a
`float` and also has a `str` representation), the appropriate
representation is selected for the column's deduced type. In order to not
lose precision accidentally, types having both an `__int__` and
`__float__` represention will be considered a `float`.

Therefore, if your table contains types convertible to int/float but you'd
*prefer* they be represented as strings, or your strings *might* all look
like numbers such as "1e23": either convert them to the desired
representation before you `tabulate`, or ensure that the column always
contains at least one other `str`.

### Text formatting

By default, `tabulate` removes leading and trailing whitespace from text
Expand Down
48 changes: 39 additions & 9 deletions tabulate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,25 +876,55 @@ def _isconvertible(conv, string):


def _isnumber(string):
"""
"""Detects if something *could* be considered a numeric value, vs. just a string.
This promotes types convertible to both int and float to be considered
a float. Note that, iff *all* values appear to be some form of numeric
value such as eg. "1e2", they would be considered numbers!
The exception is things that appear to be numbers but overflow to
+/-inf, eg. "1e23456"; we'll have to exclude them explicitly.
>>> _isnumber(123)
True
>>> _isnumber(123.45)
True
>>> _isnumber("123.45")
True
>>> _isnumber("123")
True
>>> _isnumber("spam")
False
>>> _isnumber("123e45678")
>>> _isnumber("123e45")
True
>>> _isnumber("123e45678") # evaluates equal to 'inf', but ... isn't
False
>>> _isnumber("inf")
True
>>> from fractions import Fraction
>>> _isnumber(Fraction(1,3))
True
"""
if not _isconvertible(float, string):
return False
elif isinstance(string, (str, bytes)) and (
math.isinf(float(string)) or math.isnan(float(string))
):
return string.lower() in ["inf", "-inf", "nan"]
return True
return (
# fast path
type(string) in (float, int)
# covers 'NaN', +/- 'inf', and eg. '1e2', as well as any type
# convertible to int/float.
or (
_isconvertible(float, string)
and (
# some other type convertible to float
not isinstance(string, (str, bytes))
# or, a numeric string eg. "1e1...", "NaN", ..., but isn't
# just an over/underflow
or (
not (math.isinf(float(string)) or math.isnan(float(string)))
or string.lower() in ["inf", "-inf", "nan"]
)
)
)
)


def _isint(string, inttype=int):
Expand Down

0 comments on commit 232ed74

Please sign in to comment.