Dorthu / openapi3

A Python3 OpenAPI 3 Spec Parser
BSD 3-Clause "New" or "Revised" License
118 stars 47 forks source link

openapi3.errors.SpecError when minimum/maximum validation is float #29

Closed ghost closed 3 years ago

ghost commented 3 years ago

The following file::

openapi.json ```json { "openapi": "3.0.3", "info": { "title": "Foo", "version": "1.0.0" }, "paths": { "/foo": { "post": { "responses": { "200": { "description": "Foo.", "content": { "application/json": { "schema": { "type": "object", "properties": { "value": { "type": "number", "format": "double", "minimum": 0.0, "maximum": 1.0 } } } } } } } } } } } ```

Fails to load with the following error:

Traceback ``` Traceback (most recent call last): File ".py", line 5, in api = OpenAPI(json.load(fd)) File "/openapi.py", line 44, in __init__ super(OpenAPI, self).__init__([], raw_document, self) File "/object_base.py", line 56, in __init__ self._parse_data() File "/openapi.py", line 134, in _parse_data self.paths = self._get('paths', ['Path'], is_map=True) File "/object_base.py", line 193, in _get ret = Map(self.path + [field], ret, object_types, self._root) File "/object_base.py", line 516, in __init__ dct[k] = t(path + [k], v, self._root) File "/object_base.py", line 56, in __init__ self._parse_data() File "/paths.py", line 36, in _parse_data self.post = self._get('post', 'Operation') File "/object_base.py", line 209, in _get ret = python_type(self.path + [field], ret, self._root) File "/object_base.py", line 56, in __init__ self._parse_data() File "/paths.py", line 102, in _parse_data self.responses = self._get('responses', ['Response', 'Reference'], is_map=True) File "/object_base.py", line 193, in _get ret = Map(self.path + [field], ret, object_types, self._root) File "/object_base.py", line 516, in __init__ dct[k] = t(path + [k], v, self._root) File "/object_base.py", line 56, in __init__ self._parse_data() File "/paths.py", line 385, in _parse_data self.content = self._get('content', ['MediaType'], is_map=True) File "/object_base.py", line 193, in _get ret = Map(self.path + [field], ret, object_types, self._root) File "/object_base.py", line 516, in __init__ dct[k] = t(path + [k], v, self._root) File "/object_base.py", line 56, in __init__ self._parse_data() File "/paths.py", line 365, in _parse_data self.schema = self._get('schema', ['Schema', 'Reference']) File "/object_base.py", line 209, in _get ret = python_type(self.path + [field], ret, self._root) File "/object_base.py", line 56, in __init__ self._parse_data() File "/schemas.py", line 50, in _parse_data self.properties = self._get('properties', ['Schema', 'Reference'], is_map=True) File "/object_base.py", line 193, in _get ret = Map(self.path + [field], ret, object_types, self._root) File "/object_base.py", line 516, in __init__ dct[k] = t(path + [k], v, self._root) File "/object_base.py", line 56, in __init__ self._parse_data() File "/schemas.py", line 36, in _parse_data self.maximum = self._get('maximum', int) File "/object_base.py", line 222, in _get raise SpecError('Expected {}.{} to be one of [{}], got {}'.format( openapi3.errors.SpecError: Expected paths./foo.post.responses.200.content.application/json.schema.properties.value.maximum to be one of [], got ```

The specification reads (section 5.2, validation schema):

The value of "maximum" MUST be a number, representing an upper limit for a numeric instance.

If the instance is a number, then this keyword validates if "exclusiveMaximum" is true and instance is less than the provided value, or else if the instance is less than or exactly equal to the provided value.

The same happens with minimum (and probably the exclusive* variants, didn't bother to check).

A number is (section 4.2, core schema):

number An arbitrary-precision, base-10 decimal number value, from the JSON "number" production

Thus, the code should not be checking for int but float.