Skip to content

multipleOf fails validation (decimals) #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
harmv opened this issue Sep 8, 2015 · 8 comments
Closed

multipleOf fails validation (decimals) #247

harmv opened this issue Sep 8, 2015 · 8 comments

Comments

@harmv
Copy link

harmv commented Sep 8, 2015

I noticed that json schemas with multipleOf fail to validate when using decimals.

1.1 is accepted as multiple of 0.1, but 1.9 is not.

example program that demonstrates the problem

    from jsonschema import validate, __version__
    import json

    schema = json.loads("""
    {
        "$schema": "http://json-schema.org/draft-04/schema#",
        "type": "object",
        "properties": {
            "foo": {
                "type": "number",
                "multipleOf" : 0.1
            }
        },
        "additionalProperties": false,
        "required": [
            "foo"
        ]
    }
    """)

    example1 = json.loads("""
    { "foo": 1.1}
    """)

    example2 = json.loads("""
    { "foo": 1.9}
    """)


    def main():
        print "jsonschema.__version__ = ", __version__
        validate(example1, schema)  # this one works
        validate(example2, schema)  # this should work, but doesn't

    if __name__ == "__main__":
        main()

result

jsonschema.exceptions.ValidationError: 1.9 is not a multiple of 0.1

expected result

validation passes

version

jsonschema.__version__ =  2.5.1
@Julian
Copy link
Member

Julian commented Sep 8, 2015

Hi! Thanks.

I can read this more carefully tomorrow, but from quickly glancing at that, you don't have any decimals there, you have floats. Specifically you have 1.9, which most likely is not in fact divisible by 0.1 because I suspect it's not representable exactly in binary. If you're unfamiliar and my guess is correct, you'd want to familiarize yourself with floating point (im)precision, and possibly to tell json.loads to deserialize your JSON numbers as decimal.Decimals or the like instead, if you actually want fixed or arbitrary precision.

Apologies if my guess is wrong, just let me know if you're aware of the above.

@harmv
Copy link
Author

harmv commented Sep 9, 2015

I understand In json there is no decimal, just integers and floats. the json schema above uses 'multipleOf' as a way to restrict the 'number' to 1 digit decimals.

Although it might be possible to solve this with parse_float=decimal.Decimal in json.loads (its not, see below) one could argue that jsonschema should handle this somehow. (I did not think this through, so I'm not sure this is what jsonschema should do)

What would you expect jsonschema to do here ? Handle this transparantly or not ? In my case the python code doesn't mind that the actual number is a float, thats perfectly fine. I just want to be sure that the json validates against the schema.

If you think json schema should handle this transparantly, the implementation of multipleOf could do some smarter checks if the remainder is smaller than some EPSILON.

problem with using parse_float=decimal.Decimal

When changing the code to use

example2 = json.loads("""
{ "foo": 1.9}
""",
parse_float=decimal.Decimal
)

you get the following exception

...v/lib/python2.7/site-packages/jsonschema/_validators.py", line 291, in properties_draft4 schema_path=property,
...v/lib/python2.7/site-packages/jsonschema/validators.py", line 114, in descend for error in self.iter_errors(instance, schema):
.../v/lib/python2.7/site-packages/jsonschema/validators.py", line 98, in iter_errors  for error in errors:
...v/lib/python2.7/site-packages/jsonschema/_validators.py", line 111, in multipleOf quotient = instance / dB
TypeError: unsupported operand type(s) for /: 'Decimal' and 'float

@harmv
Copy link
Author

harmv commented Sep 9, 2015

when using parse_float=decimal.Decimal also in the json.loads() of the schema itself, the above problem does not happen. then the example program works fine.

So still open, what do you want jsonschema do, in case a python program doesn't care about how it interprets the these numbers.

@Julian
Copy link
Member

Julian commented Sep 10, 2015

I don't see why jsonschema should treat floats any differently than any other program in Python personally. Users who want arbitrary precision are free to use decimal.Decimal, yeah.

@harmv
Copy link
Author

harmv commented Sep 11, 2015

Well its not the same as any other program in Python, If one wants Decimal one can indeed use it. However I see the following problem when someone don't want decimal.Decimal.They are now forced to use it, if they want to validate their json.

A program that is perfectly fine with using just floats internally (as is the default) cannot rely on validating its json with jsonschema when the schema contains multipleOf. validate might just fail (or pass) for them, while the original json string is perfectly valid.

What should such a program do ? First loads() all json with parse_float=decimal.Decimal, just be be able to validate the json? and then loads() again to use floats internally as it intended?

Not sure what the right approach is, but the current behaviour makes jsonschema hard to work with, if a schema has multipleOf=0.1.

I guess this program probably arises from the fact thatjsonschema.validate() works on python objects, instead of the actual json strings.

@Julian
Copy link
Member

Julian commented Sep 11, 2015

Anyone dealing with JSON needs to know that JSON does not have decimals, it has numbers, and they're generally deserialized as floats, so yeah people should be aware that if they want fixed precision, they need to parse JSON by specifying parse_float, which was what I meant by "it's the same as any other Python program" -- it's just JSON, you need to use it properly, same as anywhere else.

You're correct, jsonschema has very little to do with JSON in actuality :)

@Julian
Copy link
Member

Julian commented Sep 30, 2015

I'm going to close, but if you feel strongly / disagree / want to discuss more, feel free to reopen.

@Julian Julian closed this as completed Sep 30, 2015
OrangeTux pushed a commit to mobilityhouse/ocpp that referenced this issue Nov 13, 2019
The validation of payloads using jsonschemas could fail when the payload
contained a float. This problem is described in this issue:
python-jsonschema/jsonschema#247

This commit implements a work around for this issue by changing the
float parser for certain payloads from `float()` to `decimal.Decimal()`.

Fixes: #43
OrangeTux pushed a commit to mobilityhouse/ocpp that referenced this issue Nov 19, 2019
The validation of payloads using jsonschemas could fail when the payload
contained a float. This problem is described in this issue:
python-jsonschema/jsonschema#247

This commit implements a work around for this issue by changing the
float parser for certain payloads from `float()` to `decimal.Decimal()`.

Fixes: #43
OrangeTux pushed a commit to mobilityhouse/ocpp that referenced this issue Nov 19, 2019
The validation of payloads using jsonschemas could fail when the payload
contained a float. This problem is described in this issue:
python-jsonschema/jsonschema#247

This commit implements a work around for this issue by changing the
float parser for certain payloads from `float()` to `decimal.Decimal()`.

Fixes: #43
OrangeTux added a commit to mobilityhouse/ocpp that referenced this issue Nov 21, 2019
The validation of payloads using jsonschemas could fail when the payload
contained a float. This problem is described in this issue:
python-jsonschema/jsonschema#247

This commit implements a work around for this issue by changing the
float parser for certain payloads from `float()` to `decimal.Decimal()`.

Fixes: #43
RoaringDev1203 added a commit to RoaringDev1203/Cratus-OCPP that referenced this issue Aug 27, 2024
The validation of payloads using jsonschemas could fail when the payload
contained a float. This problem is described in this issue:
python-jsonschema/jsonschema#247

This commit implements a work around for this issue by changing the
float parser for certain payloads from `float()` to `decimal.Decimal()`.

Fixes: #43
ajmirsky pushed a commit to ajmirsky/ocpp that referenced this issue Nov 26, 2024
The validation of payloads using jsonschemas could fail when the payload
contained a float. This problem is described in this issue:
python-jsonschema/jsonschema#247

This commit implements a work around for this issue by changing the
float parser for certain payloads from `float()` to `decimal.Decimal()`.

Fixes: mobilityhouse#43
@jackhhh
Copy link

jackhhh commented Apr 18, 2025

I'm going to close, but if you feel strongly / disagree / want to discuss more, feel free to reopen.

There is a solution that convert float to Decimal in multipleOf keywords.

FYI: Javascript's implement tdegrunt/jsonschema#187

PR: #1349

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants