diff options
author | Julian Berman <Julian@GrayVines.com> | 2021-08-04 10:58:09 +0100 |
---|---|---|
committer | Julian Berman <Julian@GrayVines.com> | 2021-08-04 10:58:09 +0100 |
commit | 1a7a935fd3e4dc11089b0a9f6ac247d66dc6b358 (patch) | |
tree | 9ab27da280b462ac59510a715658a687c125a771 /jsonschema/_format.py | |
parent | 72a0c608f030a70c431dd1632e13d04e7370edff (diff) | |
parent | 4547b2ab8a74dd8a83c9104606b2166a9e712fa2 (diff) | |
download | jsonschema-1a7a935fd3e4dc11089b0a9f6ac247d66dc6b358.tar.gz |
Merge remote-tracking branch 'anexia-it/draft2020-12'
* anexia-it/draft2020-12:
Julian/jsonschema#782: Remove ecmascript validation, extend dynamicRef skip description
Julian/jsonschema#782: Add compatibility to draft7 and older
Julian/jsonschema#782: Code clenaup, fixes validation messages
Julian/jsonschema#782: Extend format tests
Julian/jsonschema#782: Resolve meta schema vocabularies from local cache
Julian/jsonschema#782: Refactor items behavior with prefixItems
Julian/jsonschema#782: Update validation message for unevaluatedProperties and unevaluatedItems
Julian/jsonschema#782: Fixes failing styles
Julian/jsonschema#782: Adapt validator test for draft2020-12, fixes code styles
Julian/jsonschema#782: Fixes relative json pointer format validation for leading zero on digit
Julian/jsonschema#782: Load dependencies from legacy validators
Julian/jsonschema#782: Implements dynamicRef validations
Julian/jsonschema#782: Add validation for uuid format
Julian/jsonschema#782: Implements defs validations
Julian/jsonschema#782: Extend resolver for anchor
Julian/jsonschema#782: Fixes ref resolver for folders
Julian/jsonschema#782: Fixes ref validation priority
Julian/jsonschema#782: Extend implementation of ref
Julian/jsonschema#782: Implements unevaluatedProperties validations
Julian/jsonschema#782: Implements unevaluatedItems validations
Julian/jsonschema#782: Extend contains with minContains and maxContaints, add contains legacy validator
Julian/jsonschema#782: Adapt items to work with prefixItems
Julian/jsonschema#782: Add checks for prefixItems, basic check for unevaluatedItems
Julian/jsonschema#782: Extend format check for draft2020-12, add duration format check
Julian/jsonschema#782: Add dependentRequired and dependentSchemas validation
Julian/jsonschema#782: Split format and regular test cases on draft2020-12
Julian/jsonschema#782: Enable draft2020-12 test suite
Diffstat (limited to 'jsonschema/_format.py')
-rw-r--r-- | jsonschema/_format.py | 84 |
1 files changed, 75 insertions, 9 deletions
diff --git a/jsonschema/_format.py b/jsonschema/_format.py index bdd893d..19f4283 100644 --- a/jsonschema/_format.py +++ b/jsonschema/_format.py @@ -1,3 +1,4 @@ +from uuid import UUID import datetime import ipaddress import re @@ -131,13 +132,14 @@ draft3_format_checker = FormatChecker() draft4_format_checker = FormatChecker() draft6_format_checker = FormatChecker() draft7_format_checker = FormatChecker() - +draft202012_format_checker = FormatChecker() _draft_checkers = dict( draft3=draft3_format_checker, draft4=draft4_format_checker, draft6=draft6_format_checker, draft7=draft7_format_checker, + draft202012=draft202012_format_checker, ) @@ -147,12 +149,14 @@ def _checks_drafts( draft4=None, draft6=None, draft7=None, + draft202012=None, raises=(), ): draft3 = draft3 or name draft4 = draft4 or name draft6 = draft6 or name draft7 = draft7 or name + draft202012 = draft202012 or name def wrap(func): if draft3: @@ -163,13 +167,17 @@ def _checks_drafts( func = _draft_checkers["draft6"].checks(draft6, raises)(func) if draft7: func = _draft_checkers["draft7"].checks(draft7, raises)(func) + if draft202012: + func = _draft_checkers["draft202012"].checks( + draft202012, raises + )(func) # Oy. This is bad global state, but relied upon for now, until # deprecation. See https://github.com/Julian/jsonschema/issues/519 # and test_format_checkers_come_with_defaults - FormatChecker.cls_checks(draft7 or draft6 or draft4 or draft3, raises)( - func, - ) + FormatChecker.cls_checks( + draft202012 or draft7 or draft6 or draft4 or draft3, raises + )(func) return func return wrap @@ -187,6 +195,7 @@ def is_email(instance): draft4="ipv4", draft6="ipv4", draft7="ipv4", + draft202012="ipv4", raises=ipaddress.AddressValueError, ) def is_ipv4(instance): @@ -213,6 +222,7 @@ else: draft4="hostname", draft6="hostname", draft7="hostname", + draft202012="hostname", ) def is_host_name(instance): if not isinstance(instance, str): @@ -228,6 +238,7 @@ except ImportError: # pragma: no cover else: @_checks_drafts( draft7="idn-hostname", + draft202012="idn-hostname", raises=(idna.IDNAError, UnicodeError), ) def is_idn_host_name(instance): @@ -254,6 +265,7 @@ except ImportError: @_checks_drafts( draft6="uri-reference", draft7="uri-reference", + draft202012="uri-reference", raises=ValueError, ) def is_uri_reference(instance): @@ -262,19 +274,30 @@ except ImportError: return validate_rfc3986(instance, rule="URI_reference") else: - @_checks_drafts(draft7="iri", raises=ValueError) + @_checks_drafts( + draft7="iri", + draft202012="iri", + raises=ValueError, + ) def is_iri(instance): if not isinstance(instance, str): return True return rfc3987.parse(instance, rule="IRI") - @_checks_drafts(draft7="iri-reference", raises=ValueError) + @_checks_drafts( + draft7="iri-reference", + draft202012="iri-reference", + raises=ValueError, + ) def is_iri_reference(instance): if not isinstance(instance, str): return True return rfc3987.parse(instance, rule="IRI_reference") - @_checks_drafts(name="uri", raises=ValueError) + @_checks_drafts( + name="uri", + raises=ValueError, + ) def is_uri(instance): if not isinstance(instance, str): return True @@ -283,6 +306,7 @@ else: @_checks_drafts( draft6="uri-reference", draft7="uri-reference", + draft202012="uri-reference", raises=ValueError, ) def is_uri_reference(instance): @@ -306,7 +330,10 @@ if validate_rfc3339: return True return validate_rfc3339(instance.upper()) - @_checks_drafts(draft7="time") + @_checks_drafts( + draft7="time", + draft202012="time", + ) def is_time(instance): if not isinstance(instance, str): return True @@ -327,7 +354,12 @@ else: return datetime.datetime.strptime(instance, "%Y-%m-%d") -@_checks_drafts(draft3="date", draft7="date", raises=ValueError) +@_checks_drafts( + draft3="date", + draft7="date", + draft202012="date", + raises=ValueError, +) def is_date(instance): if not isinstance(instance, str): return True @@ -377,6 +409,7 @@ else: @_checks_drafts( draft6="json-pointer", draft7="json-pointer", + draft202012="json-pointer", raises=jsonpointer.JsonPointerException, ) def is_json_pointer(instance): @@ -390,6 +423,7 @@ else: # into a new external library. @_checks_drafts( draft7="relative-json-pointer", + draft202012="relative-json-pointer", raises=jsonpointer.JsonPointerException, ) def is_relative_json_pointer(instance): @@ -400,6 +434,10 @@ else: non_negative_integer, rest = [], "" for i, character in enumerate(instance): if character.isdigit(): + # digits with a leading "0" are not allowed + if i > 0 and int(instance[i-1]) == 0: + return False + non_negative_integer.append(character) continue @@ -419,8 +457,36 @@ else: @_checks_drafts( draft6="uri-template", draft7="uri-template", + draft202012="uri-template", ) def is_uri_template(instance): if not isinstance(instance, str): return True return uri_template.validate(instance) + + +try: + import isoduration +except ImportError: # pragma: no cover + pass +else: + @_checks_drafts( + draft202012="duration", + raises=isoduration.DurationParsingException, + ) + def is_duration(instance): + if not isinstance(instance, str): + return True + return isoduration.parse_duration(instance) + + +@_checks_drafts( + draft202012="uuid", + raises=ValueError, +) +def is_uuid(instance): + if not isinstance(instance, str): + return True + if "-" not in instance: + raise ValueError("Invalid UUID format") + return UUID(instance) |