Skip to content

Commit cd1f06e

Browse files
authored
Merge pull request #126 from abravalheri/add-custom-formats-arg
Add `custom_formats` argument to generated code
2 parents d4a5eb2 + 7e01c7b commit cd1f06e

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

Diff for: fastjsonschema/__init__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
API
7676
***
7777
"""
78+
from functools import partial, update_wrapper
7879

7980
from .draft04 import CodeGeneratorDraft04
8081
from .draft06 import CodeGeneratorDraft06
@@ -177,7 +178,10 @@ def compile(definition, handlers={}, formats={}, use_default=True):
177178
global_state = code_generator.global_state
178179
# Do not pass local state so it can recursively call itself.
179180
exec(code_generator.func_code, global_state)
180-
return global_state[resolver.get_scope_name()]
181+
func = global_state[resolver.get_scope_name()]
182+
if formats:
183+
return update_wrapper(partial(func, custom_formats=formats), func)
184+
return func
181185

182186

183187
# pylint: disable=dangerous-default-value

Diff for: fastjsonschema/generator.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class CodeGenerator:
3232
def __init__(self, definition, resolver=None):
3333
self._code = []
3434
self._compile_regexps = {}
35+
self._custom_formats = {}
3536

3637
# Any extra library should be here to be imported only once.
3738
# Lines are imports to be printed in the file and objects
@@ -136,7 +137,7 @@ def generate_validation_function(self, uri, name):
136137
self._validation_functions_done.add(uri)
137138
self.l('')
138139
with self._resolver.resolving(uri) as definition:
139-
with self.l('def {}(data):', name):
140+
with self.l('def {}(data, custom_formats={{}}):', name):
140141
self.generate_func_code_block(definition, 'data', 'data', clear_variables=True)
141142
self.l('return data')
142143

@@ -190,7 +191,7 @@ def generate_ref(self):
190191
if uri not in self._validation_functions_done:
191192
self._needed_validation_functions[uri] = name
192193
# call validation function
193-
self.l('{}({variable})', name)
194+
self.l('{}({variable}, custom_formats)', name)
194195

195196

196197
# pylint: disable=invalid-name

Diff for: tests/test_compile_to_code.py

+38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import pytest
33
import shutil
44

5+
from fastjsonschema import JsonSchemaValueException
56
from fastjsonschema import compile_to_code, compile as compile_spec
67

78
@pytest.yield_fixture(autouse=True)
@@ -84,3 +85,40 @@ def test_compile_complex_one_of_all_of():
8485
}
8586
]
8687
})
88+
89+
90+
def test_compile_to_code_custom_format():
91+
formats = {'my-format': str.isidentifier}
92+
code = compile_to_code({'type': 'string', 'format': 'my-format'}, formats=formats)
93+
with open('temp/schema_3.py', 'w') as f:
94+
f.write(code)
95+
from temp.schema_3 import validate
96+
assert validate("valid", formats) == "valid"
97+
with pytest.raises(JsonSchemaValueException) as exc:
98+
validate("not-valid", formats)
99+
assert exc.value.message == "data must be my-format"
100+
101+
102+
def test_compile_to_code_custom_format_with_refs():
103+
schema = {
104+
'type': 'object',
105+
'properties': {
106+
'a': {'$ref': '#/definitions/a'}
107+
},
108+
'definitions': {
109+
'a': {
110+
'$id': '#/definitions/a',
111+
'type': 'array',
112+
'items': {'type': 'string', 'format': 'my-format'}
113+
}
114+
}
115+
}
116+
formats = {'my-format': str.isidentifier}
117+
code = compile_to_code(schema, formats=formats)
118+
with open('temp/schema_4.py', 'w') as f:
119+
f.write(code)
120+
from temp.schema_4 import validate
121+
assert validate({"a": ["identifier"]}, formats) is not None
122+
with pytest.raises(JsonSchemaValueException) as exc:
123+
validate({"a": ["identifier", "not-valid"]}, formats)
124+
assert exc.value.message == "data[1] must be my-format"

0 commit comments

Comments
 (0)