keleshev / schema

Schema validation just got Pythonic
MIT License
2.86k stars 214 forks source link

number vs float #287

Closed mjm987 closed 1 year ago

mjm987 commented 1 year ago

I guess json number should allow floating point values (with a decimal point) as well as integer values (without decimal point). But not so this schema library: if I specify a "float" type in the schema, it allows numbers with a decimal point only. Values without a decimal point results in a error.

LandingEllipse commented 1 year ago

JSON does not on its own distinguish between integers and floating-point values. Python's builtin json library, however, will cast numbers without a fractional component to int, and those with to float (along with numbers expressed in exponent notation). For instance:

>>> nums = json.loads("[1, 1.0]")
>>> nums
[1, 1.0]
>>> [type(n) for n in nums]
[<class 'int'>, <class 'float'>]

When you specify a float type in a schema, you're effectively asking for an isinstance(..., float) check to be performed, which of course will fail for numbers cast as int:

>>> import schema
>>> schema.Schema([float]).validate(nums)
Traceback (most recent call last):
  (...)
1 should be instance of 'float'

You have a couple of options for how to handle this, depending on the needs of your application. If you're happy for numbers to be either int or float, use schema.Or, e.g.:

>>> schema.Schema([schema.Or(int, float)]).validate(nums)
[1, 1.0]

If you'd rather force ints to be cast as floats, schema.Use is what you're looking for. For instance:

>>> schema.Schema([schema.Use(float)]).validate(nums)
[1.0, 1.0]

schema.Use here essentially amounts to [float(n) for n in nums].

I hope this helps!

mjm987 commented 1 year ago

Great! Many thanks for the solutions and the detailed explanations!