Skip to content

Commit

Permalink
Added use_formats parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
horejsek committed Nov 14, 2023
1 parent b0645bf commit 38e0116
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
=== 2.19.0 (2023-11-14)

* Added `use_formats` parameter to allow disable automatic assertions

=== 2.18.1 (2023-10-01)

* Lazy import of urllib to improve import performance
Expand Down
19 changes: 12 additions & 7 deletions fastjsonschema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
)


def validate(definition, data, handlers={}, formats={}, use_default=True):
def validate(definition, data, handlers={}, formats={}, use_default=True, use_formats=True):
"""
Validation function for lazy programmers or for use cases when you need
to call validation only once, so you do not have to compile it first.
Expand All @@ -139,12 +139,12 @@ def validate(definition, data, handlers={}, formats={}, use_default=True):
Preferred is to use :any:`compile` function.
"""
return compile(definition, handlers, formats, use_default)(data)
return compile(definition, handlers, formats, use_default, use_formats)(data)


#TODO: Change use_default to False when upgrading to version 3.
# pylint: disable=redefined-builtin,dangerous-default-value,exec-used
def compile(definition, handlers={}, formats={}, use_default=True):
def compile(definition, handlers={}, formats={}, use_default=True, use_formats=True):
"""
Generates validation function for validating JSON schema passed in ``definition``.
Example:
Expand Down Expand Up @@ -196,13 +196,17 @@ def compile(definition, handlers={}, formats={}, use_default=True):
'bar': lambda value: value in ('foo', 'bar'),
})
Note that formats are automatically used as assertions. It can be turned
off by passing `use_formats=False`. When disabled, custom formats are
disabled as well. (Added in 2.19.0.)
Exception :any:`JsonSchemaDefinitionException` is raised when generating the
code fails (bad definition).
Exception :any:`JsonSchemaValueException` is raised from generated function when
validation fails (data do not follow the definition).
"""
resolver, code_generator = _factory(definition, handlers, formats, use_default)
resolver, code_generator = _factory(definition, handlers, formats, use_default, use_formats)
global_state = code_generator.global_state
# Do not pass local state so it can recursively call itself.
exec(code_generator.func_code, global_state)
Expand All @@ -213,7 +217,7 @@ def compile(definition, handlers={}, formats={}, use_default=True):


# pylint: disable=dangerous-default-value
def compile_to_code(definition, handlers={}, formats={}, use_default=True):
def compile_to_code(definition, handlers={}, formats={}, use_default=True, use_formats=True):
"""
Generates validation code for validating JSON schema passed in ``definition``.
Example:
Expand All @@ -236,21 +240,22 @@ def compile_to_code(definition, handlers={}, formats={}, use_default=True):
Exception :any:`JsonSchemaDefinitionException` is raised when generating the
code fails (bad definition).
"""
_, code_generator = _factory(definition, handlers, formats, use_default)
_, code_generator = _factory(definition, handlers, formats, use_default, use_formats)
return (
'VERSION = "' + VERSION + '"\n' +
code_generator.global_state_code + '\n' +
code_generator.func_code
)


def _factory(definition, handlers, formats={}, use_default=True):
def _factory(definition, handlers, formats={}, use_default=True, use_formats=True):
resolver = RefResolver.from_schema(definition, handlers=handlers, store={})
code_generator = _get_code_generator_class(definition)(
definition,
resolver=resolver,
formats=formats,
use_default=use_default,
use_formats=use_formats,
)
return resolver, code_generator

Expand Down
5 changes: 4 additions & 1 deletion fastjsonschema/draft04.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ class CodeGeneratorDraft04(CodeGenerator):
'uri': r'^\w+:(\/?\/?)[^\s]+\Z',
}

def __init__(self, definition, resolver=None, formats={}, use_default=True):
def __init__(self, definition, resolver=None, formats={}, use_default=True, use_formats=True):
super().__init__(definition, resolver)
self._custom_formats = formats
self._use_formats = use_formats
self._use_default = use_default
self._json_keywords_to_function.update((
('type', self.generate_type),
Expand Down Expand Up @@ -254,6 +255,8 @@ def generate_format(self):
Valid value for this definition is [email protected] but not @username
"""
if not self._use_formats:
return
with self.l('if isinstance({variable}, str):'):
format_ = self._definition['format']
# Checking custom formats - user is allowed to override default formats.
Expand Down
4 changes: 2 additions & 2 deletions fastjsonschema/draft06.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class CodeGeneratorDraft06(CodeGeneratorDraft04):
),
})

def __init__(self, definition, resolver=None, formats={}, use_default=True):
super().__init__(definition, resolver, formats, use_default)
def __init__(self, definition, resolver=None, formats={}, use_default=True, use_formats=True):
super().__init__(definition, resolver, formats, use_default, use_formats)
self._json_keywords_to_function.update((
('exclusiveMinimum', self.generate_exclusive_minimum),
('exclusiveMaximum', self.generate_exclusive_maximum),
Expand Down
4 changes: 2 additions & 2 deletions fastjsonschema/draft07.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class CodeGeneratorDraft07(CodeGeneratorDraft06):
),
})

def __init__(self, definition, resolver=None, formats={}, use_default=True):
super().__init__(definition, resolver, formats, use_default)
def __init__(self, definition, resolver=None, formats={}, use_default=True, use_formats=True):
super().__init__(definition, resolver, formats, use_default, use_formats)
# pylint: disable=duplicate-code
self._json_keywords_to_function.update((
('if', self.generate_if_then_else),
Expand Down
2 changes: 1 addition & 1 deletion fastjsonschema/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = '2.18.1'
VERSION = '2.19.0'
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ def pytest_configure(config):

@pytest.fixture
def asserter():
def f(definition, value, expected, formats={}):
def f(definition, value, expected, formats={}, use_formats=True):
# When test fails, it will show up code.
code_generator = CodeGeneratorDraft07(definition, formats=formats)
code_generator = CodeGeneratorDraft07(definition, formats=formats, use_formats=use_formats)
print(code_generator.func_code)
pprint(code_generator.global_state)

# By default old tests are written for draft-04.
definition.setdefault('$schema', 'http://json-schema.org/draft-04/schema')

validator = compile(definition, formats=formats)
validator = compile(definition, formats=formats, use_formats=use_formats)
if isinstance(expected, JsonSchemaValueException):
with pytest.raises(JsonSchemaValueException) as exc:
validator(value)
Expand Down
5 changes: 5 additions & 0 deletions tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,8 @@ def test_custom_format_override(asserter):
asserter({'format': 'date-time'}, 'a', 'a', formats={
'date-time': r'^[ab]$',
})


def test_disable_formats(asserter):
asserter({'format': 'date-time'}, 'bla', 'bla', use_formats=False)

0 comments on commit 38e0116

Please sign in to comment.