Skip to content

Commit 1df6246

Browse files
authored
Merge pull request #170 from pbabics/feature/number-decimal
Add support for `decimal.Decimal` as number
2 parents ddbf84e + 1e27499 commit 1df6246

File tree

4 files changed

+36
-17
lines changed

4 files changed

+36
-17
lines changed

fastjsonschema/draft04.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
JSON_TYPE_TO_PYTHON_TYPE = {
99
'null': 'NoneType',
1010
'boolean': 'bool',
11-
'number': 'int, float',
11+
'number': 'int, float, Decimal',
1212
'integer': 'int',
1313
'string': 'str',
1414
'array': 'list, tuple',
@@ -285,8 +285,8 @@ def _generate_format(self, format_name, regexp_name, regexp):
285285
self.exc('{name} must be {}', format_name, rule='format')
286286

287287
def generate_minimum(self):
288-
with self.l('if isinstance({variable}, (int, float)):'):
289-
if not isinstance(self._definition['minimum'], (int, float)):
288+
with self.l('if isinstance({variable}, (int, float, Decimal)):'):
289+
if not isinstance(self._definition['minimum'], (int, float, decimal.Decimal)):
290290
raise JsonSchemaDefinitionException('minimum must be a number')
291291
if self._definition.get('exclusiveMinimum', False):
292292
with self.l('if {variable} <= {minimum}:'):
@@ -296,8 +296,8 @@ def generate_minimum(self):
296296
self.exc('{name} must be bigger than or equal to {minimum}', rule='minimum')
297297

298298
def generate_maximum(self):
299-
with self.l('if isinstance({variable}, (int, float)):'):
300-
if not isinstance(self._definition['maximum'], (int, float)):
299+
with self.l('if isinstance({variable}, (int, float, Decimal)):'):
300+
if not isinstance(self._definition['maximum'], (int, float, decimal.Decimal)):
301301
raise JsonSchemaDefinitionException('maximum must be a number')
302302
if self._definition.get('exclusiveMaximum', False):
303303
with self.l('if {variable} >= {maximum}:'):
@@ -307,14 +307,12 @@ def generate_maximum(self):
307307
self.exc('{name} must be smaller than or equal to {maximum}', rule='maximum')
308308

309309
def generate_multiple_of(self):
310-
with self.l('if isinstance({variable}, (int, float)):'):
311-
if not isinstance(self._definition['multipleOf'], (int, float)):
310+
with self.l('if isinstance({variable}, (int, float, Decimal)):'):
311+
if not isinstance(self._definition['multipleOf'], (int, float, decimal.Decimal)):
312312
raise JsonSchemaDefinitionException('multipleOf must be a number')
313313
# For proper multiplication check of floats we need to use decimals,
314314
# because for example 19.01 / 0.01 = 1901.0000000000002.
315315
if isinstance(self._definition['multipleOf'], float):
316-
self._extra_imports_lines.append('from decimal import Decimal')
317-
self._extra_imports_objects['Decimal'] = decimal.Decimal
318316
self.l('quotient = Decimal(repr({variable})) / Decimal(repr({multipleOf}))')
319317
else:
320318
self.l('quotient = {variable} / {multipleOf}')

fastjsonschema/draft06.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import decimal
12
from .draft04 import CodeGeneratorDraft04, JSON_TYPE_TO_PYTHON_TYPE
23
from .exceptions import JsonSchemaDefinitionException
34
from .generator import enforce_list
@@ -73,16 +74,16 @@ def generate_type(self):
7374
self.exc('{name} must be {}', ' or '.join(types), rule='type')
7475

7576
def generate_exclusive_minimum(self):
76-
with self.l('if isinstance({variable}, (int, float)):'):
77-
if not isinstance(self._definition['exclusiveMinimum'], (int, float)):
78-
raise JsonSchemaDefinitionException('exclusiveMinimum must be an integer or a float')
77+
with self.l('if isinstance({variable}, (int, float, Decimal)):'):
78+
if not isinstance(self._definition['exclusiveMinimum'], (int, float, decimal.Decimal)):
79+
raise JsonSchemaDefinitionException('exclusiveMinimum must be an integer, a float or a decimal')
7980
with self.l('if {variable} <= {exclusiveMinimum}:'):
8081
self.exc('{name} must be bigger than {exclusiveMinimum}', rule='exclusiveMinimum')
8182

8283
def generate_exclusive_maximum(self):
83-
with self.l('if isinstance({variable}, (int, float)):'):
84-
if not isinstance(self._definition['exclusiveMaximum'], (int, float)):
85-
raise JsonSchemaDefinitionException('exclusiveMaximum must be an integer or a float')
84+
with self.l('if isinstance({variable}, (int, float, Decimal)):'):
85+
if not isinstance(self._definition['exclusiveMaximum'], (int, float, decimal.Decimal)):
86+
raise JsonSchemaDefinitionException('exclusiveMaximum must be an integer, a float or a decimal')
8687
with self.l('if {variable} >= {exclusiveMaximum}:'):
8788
self.exc('{name} must be smaller than {exclusiveMaximum}', rule='exclusiveMaximum')
8889

fastjsonschema/generator.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections import OrderedDict
2+
from decimal import Decimal
23
import re
34

45
from .exceptions import JsonSchemaValueException, JsonSchemaDefinitionException
@@ -36,8 +37,12 @@ def __init__(self, definition, resolver=None):
3637
# Any extra library should be here to be imported only once.
3738
# Lines are imports to be printed in the file and objects
3839
# key-value pair to pass to compile function directly.
39-
self._extra_imports_lines = []
40-
self._extra_imports_objects = {}
40+
self._extra_imports_lines = [
41+
"from decimal import Decimal",
42+
]
43+
self._extra_imports_objects = {
44+
"Decimal": Decimal,
45+
}
4146

4247
self._variables = set()
4348
self._indent = 0

tests/test_number.py

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import decimal
2+
13
import pytest
24

35
from fastjsonschema import JsonSchemaValueException
@@ -161,3 +163,16 @@ def test_number_allows_float(asserter, value):
161163
asserter({
162164
'type': 'number',
163165
}, value, value)
166+
167+
168+
169+
@pytest.mark.parametrize('value', (
170+
decimal.Decimal('1.0'),
171+
decimal.Decimal('0.1'),
172+
decimal.Decimal('0.01'),
173+
decimal.Decimal('0.001'),
174+
))
175+
def test_number_allows_decimal(asserter, value):
176+
asserter({
177+
'type': 'number',
178+
}, value, value)

0 commit comments

Comments
 (0)