@@ -876,25 +876,55 @@ def _isconvertible(conv, string):
876876
877877
878878def _isnumber (string ):
879- """
879+ """Detects if something *could* be considered a numeric value, vs. just a string.
880+
881+ This promotes types convertible to both int and float to be considered
882+ a float. Note that, iff *all* values appear to be some form of numeric
883+ value such as eg. "1e2", they would be considered numbers!
884+
885+ The exception is things that appear to be numbers but overflow to
886+ +/-inf, eg. "1e23456"; we'll have to exclude them explicitly.
887+
888+ >>> _isnumber(123)
889+ True
890+ >>> _isnumber(123.45)
891+ True
880892 >>> _isnumber("123.45")
881893 True
882894 >>> _isnumber("123")
883895 True
884896 >>> _isnumber("spam")
885897 False
886- >>> _isnumber("123e45678")
898+ >>> _isnumber("123e45")
899+ True
900+ >>> _isnumber("123e45678") # evaluates equal to 'inf', but ... isn't
887901 False
888902 >>> _isnumber("inf")
889903 True
904+ >>> from fractions import Fraction
905+ >>> _isnumber(Fraction(1,3))
906+ True
907+
890908 """
891- if not _isconvertible (float , string ):
892- return False
893- elif isinstance (string , (str , bytes )) and (
894- math .isinf (float (string )) or math .isnan (float (string ))
895- ):
896- return string .lower () in ["inf" , "-inf" , "nan" ]
897- return True
909+ return (
910+ # fast path
911+ type (string ) in (float , int )
912+ # covers 'NaN', +/- 'inf', and eg. '1e2', as well as any type
913+ # convertible to int/float.
914+ or (
915+ _isconvertible (float , string )
916+ and (
917+ # some other type convertible to float
918+ not isinstance (string , (str , bytes ))
919+ # or, a numeric string eg. "1e1...", "NaN", ..., but isn't
920+ # just an over/underflow
921+ or (
922+ not (math .isinf (float (string )) or math .isnan (float (string )))
923+ or string .lower () in ["inf" , "-inf" , "nan" ]
924+ )
925+ )
926+ )
927+ )
898928
899929
900930def _isint (string , inttype = int ):
0 commit comments