aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/jsonschema
diff options
context:
space:
mode:
authormaxim-yurchuk <maxim-yurchuk@yandex-team.com>2024-10-09 12:29:46 +0300
committermaxim-yurchuk <maxim-yurchuk@yandex-team.com>2024-10-09 13:14:22 +0300
commit9731d8a4bb7ee2cc8554eaf133bb85498a4c7d80 (patch)
treea8fb3181d5947c0d78cf402aa56e686130179049 /contrib/python/jsonschema
parenta44b779cd359f06c3ebbef4ec98c6b38609d9d85 (diff)
downloadydb-9731d8a4bb7ee2cc8554eaf133bb85498a4c7d80.tar.gz
publishFullContrib: true for ydb
<HIDDEN_URL> commit_hash:c82a80ac4594723cebf2c7387dec9c60217f603e
Diffstat (limited to 'contrib/python/jsonschema')
-rw-r--r--contrib/python/jsonschema/py2/.yandex_meta/yamaker.yaml4
-rw-r--r--contrib/python/jsonschema/py2/jsonschema/benchmarks/__init__.py5
-rw-r--r--contrib/python/jsonschema/py2/jsonschema/benchmarks/issue232.py26
-rw-r--r--contrib/python/jsonschema/py2/jsonschema/benchmarks/json_schema_test_suite.py14
-rw-r--r--contrib/python/jsonschema/py2/jsonschema/tests/_suite.py239
-rw-r--r--contrib/python/jsonschema/py2/jsonschema/tests/test_jsonschema_test_suite.py277
-rw-r--r--contrib/python/jsonschema/py2/patches/01-fix-tests.patch23
-rw-r--r--contrib/python/jsonschema/py3/.yandex_meta/yamaker.yaml4
-rw-r--r--contrib/python/jsonschema/py3/jsonschema/benchmarks/__init__.py5
-rw-r--r--contrib/python/jsonschema/py3/jsonschema/benchmarks/issue232.py26
-rw-r--r--contrib/python/jsonschema/py3/jsonschema/benchmarks/json_schema_test_suite.py14
-rw-r--r--contrib/python/jsonschema/py3/jsonschema/tests/_suite.py239
-rw-r--r--contrib/python/jsonschema/py3/jsonschema/tests/test_jsonschema_test_suite.py277
-rw-r--r--contrib/python/jsonschema/py3/patches/01-fix-tests.patch23
-rw-r--r--contrib/python/jsonschema/py3/patches/02-support-python-3.12.patch8
15 files changed, 1184 insertions, 0 deletions
diff --git a/contrib/python/jsonschema/py2/.yandex_meta/yamaker.yaml b/contrib/python/jsonschema/py2/.yandex_meta/yamaker.yaml
new file mode 100644
index 0000000000..da6fd45b32
--- /dev/null
+++ b/contrib/python/jsonschema/py2/.yandex_meta/yamaker.yaml
@@ -0,0 +1,4 @@
+exclude:
+ - json/*
+mark_as_tests:
+ - jsonschema/benchmarks/*
diff --git a/contrib/python/jsonschema/py2/jsonschema/benchmarks/__init__.py b/contrib/python/jsonschema/py2/jsonschema/benchmarks/__init__.py
new file mode 100644
index 0000000000..e3dcc68993
--- /dev/null
+++ b/contrib/python/jsonschema/py2/jsonschema/benchmarks/__init__.py
@@ -0,0 +1,5 @@
+"""
+Benchmarks for validation.
+
+This package is *not* public API.
+"""
diff --git a/contrib/python/jsonschema/py2/jsonschema/benchmarks/issue232.py b/contrib/python/jsonschema/py2/jsonschema/benchmarks/issue232.py
new file mode 100644
index 0000000000..65e3aedf79
--- /dev/null
+++ b/contrib/python/jsonschema/py2/jsonschema/benchmarks/issue232.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+"""
+A performance benchmark using the example from issue #232.
+
+See https://github.com/Julian/jsonschema/pull/232.
+"""
+from twisted.python.filepath import FilePath
+from pyperf import Runner
+from pyrsistent import m
+
+from jsonschema.tests._suite import Version
+import jsonschema
+
+
+issue232 = Version(
+ path=FilePath(__file__).sibling("issue232"),
+ remotes=m(),
+ name="issue232",
+)
+
+
+if __name__ == "__main__":
+ issue232.benchmark(
+ runner=Runner(),
+ Validator=jsonschema.Draft4Validator,
+ )
diff --git a/contrib/python/jsonschema/py2/jsonschema/benchmarks/json_schema_test_suite.py b/contrib/python/jsonschema/py2/jsonschema/benchmarks/json_schema_test_suite.py
new file mode 100644
index 0000000000..5add5051df
--- /dev/null
+++ b/contrib/python/jsonschema/py2/jsonschema/benchmarks/json_schema_test_suite.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+"""
+A performance benchmark using the official test suite.
+
+This benchmarks jsonschema using every valid example in the
+JSON-Schema-Test-Suite. It will take some time to complete.
+"""
+from pyperf import Runner
+
+from jsonschema.tests._suite import Suite
+
+
+if __name__ == "__main__":
+ Suite().benchmark(runner=Runner())
diff --git a/contrib/python/jsonschema/py2/jsonschema/tests/_suite.py b/contrib/python/jsonschema/py2/jsonschema/tests/_suite.py
new file mode 100644
index 0000000000..b68a7b668c
--- /dev/null
+++ b/contrib/python/jsonschema/py2/jsonschema/tests/_suite.py
@@ -0,0 +1,239 @@
+"""
+Python representations of the JSON Schema Test Suite tests.
+"""
+
+from functools import partial
+import json
+import os
+import re
+import subprocess
+import sys
+import unittest
+
+from twisted.python.filepath import FilePath
+import attr
+
+from jsonschema.compat import PY3
+from jsonschema.validators import validators
+import jsonschema
+
+
+def _find_suite():
+ root = os.environ.get("JSON_SCHEMA_TEST_SUITE")
+ if root is not None:
+ return FilePath(root)
+
+ root = FilePath(jsonschema.__file__).parent().sibling("json")
+ if not root.isdir(): # pragma: no cover
+ raise ValueError(
+ (
+ "Can't find the JSON-Schema-Test-Suite directory. "
+ "Set the 'JSON_SCHEMA_TEST_SUITE' environment "
+ "variable or run the tests from alongside a checkout "
+ "of the suite."
+ ),
+ )
+ return root
+
+
+@attr.s(hash=True)
+class Suite(object):
+
+ _root = attr.ib(default=attr.Factory(_find_suite))
+
+ def _remotes(self):
+ jsonschema_suite = self._root.descendant(["bin", "jsonschema_suite"])
+ remotes = subprocess.check_output(
+ [sys.executable, jsonschema_suite.path, "remotes"],
+ )
+ return {
+ "http://localhost:1234/" + name: schema
+ for name, schema in json.loads(remotes.decode("utf-8")).items()
+ }
+
+ def benchmark(self, runner): # pragma: no cover
+ for name in validators:
+ self.version(name=name).benchmark(runner=runner)
+
+ def version(self, name):
+ return Version(
+ name=name,
+ path=self._root.descendant(["tests", name]),
+ remotes=self._remotes(),
+ )
+
+
+@attr.s(hash=True)
+class Version(object):
+
+ _path = attr.ib()
+ _remotes = attr.ib()
+
+ name = attr.ib()
+
+ def benchmark(self, runner, **kwargs): # pragma: no cover
+ for suite in self.tests():
+ for test in suite:
+ runner.bench_func(
+ test.fully_qualified_name,
+ partial(test.validate_ignoring_errors, **kwargs),
+ )
+
+ def tests(self):
+ return (
+ test
+ for child in self._path.globChildren("*.json")
+ for test in self._tests_in(
+ subject=child.basename()[:-5],
+ path=child,
+ )
+ )
+
+ def format_tests(self):
+ path = self._path.descendant(["optional", "format"])
+ return (
+ test
+ for child in path.globChildren("*.json")
+ for test in self._tests_in(
+ subject=child.basename()[:-5],
+ path=child,
+ )
+ )
+
+ def tests_of(self, name):
+ return self._tests_in(
+ subject=name,
+ path=self._path.child(name + ".json"),
+ )
+
+ def optional_tests_of(self, name):
+ return self._tests_in(
+ subject=name,
+ path=self._path.descendant(["optional", name + ".json"]),
+ )
+
+ def to_unittest_testcase(self, *suites, **kwargs):
+ name = kwargs.pop("name", "Test" + self.name.title())
+ methods = {
+ test.method_name: test.to_unittest_method(**kwargs)
+ for suite in suites
+ for tests in suite
+ for test in tests
+ }
+ cls = type(name, (unittest.TestCase,), methods)
+
+ try:
+ cls.__module__ = _someone_save_us_the_module_of_the_caller()
+ except Exception: # pragma: no cover
+ # We're doing crazy things, so if they go wrong, like a function
+ # behaving differently on some other interpreter, just make them
+ # not happen.
+ pass
+
+ return cls
+
+ def _tests_in(self, subject, path):
+ for each in json.loads(path.getContent().decode("utf-8")):
+ yield (
+ _Test(
+ version=self,
+ subject=subject,
+ case_description=each["description"],
+ schema=each["schema"],
+ remotes=self._remotes,
+ **test
+ ) for test in each["tests"]
+ )
+
+
+@attr.s(hash=True, repr=False)
+class _Test(object):
+
+ version = attr.ib()
+
+ subject = attr.ib()
+ case_description = attr.ib()
+ description = attr.ib()
+
+ data = attr.ib()
+ schema = attr.ib(repr=False)
+
+ valid = attr.ib()
+
+ _remotes = attr.ib()
+
+ def __repr__(self): # pragma: no cover
+ return "<Test {}>".format(self.fully_qualified_name)
+
+ @property
+ def fully_qualified_name(self): # pragma: no cover
+ return " > ".join(
+ [
+ self.version.name,
+ self.subject,
+ self.case_description,
+ self.description,
+ ]
+ )
+
+ @property
+ def method_name(self):
+ delimiters = r"[\W\- ]+"
+ name = "test_%s_%s_%s" % (
+ re.sub(delimiters, "_", self.subject),
+ re.sub(delimiters, "_", self.case_description),
+ re.sub(delimiters, "_", self.description),
+ )
+
+ if not PY3: # pragma: no cover
+ name = name.encode("utf-8")
+ return name
+
+ def to_unittest_method(self, skip=lambda test: None, **kwargs):
+ if self.valid:
+ def fn(this):
+ self.validate(**kwargs)
+ else:
+ def fn(this):
+ with this.assertRaises(jsonschema.ValidationError):
+ self.validate(**kwargs)
+
+ fn.__name__ = self.method_name
+ reason = skip(self)
+ return unittest.skipIf(reason is not None, reason)(fn)
+
+ def validate(self, Validator, **kwargs):
+ resolver = jsonschema.RefResolver.from_schema(
+ schema=self.schema,
+ store=self._remotes,
+ id_of=Validator.ID_OF,
+ )
+ jsonschema.validate(
+ instance=self.data,
+ schema=self.schema,
+ cls=Validator,
+ resolver=resolver,
+ **kwargs
+ )
+
+ def validate_ignoring_errors(self, Validator): # pragma: no cover
+ try:
+ self.validate(Validator=Validator)
+ except jsonschema.ValidationError:
+ pass
+
+
+def _someone_save_us_the_module_of_the_caller():
+ """
+ The FQON of the module 2nd stack frames up from here.
+
+ This is intended to allow us to dynamicallly return test case classes that
+ are indistinguishable from being defined in the module that wants them.
+
+ Otherwise, trial will mis-print the FQON, and copy pasting it won't re-run
+ the class that really is running.
+
+ Save us all, this is all so so so so so terrible.
+ """
+
+ return sys._getframe(2).f_globals["__name__"]
diff --git a/contrib/python/jsonschema/py2/jsonschema/tests/test_jsonschema_test_suite.py b/contrib/python/jsonschema/py2/jsonschema/tests/test_jsonschema_test_suite.py
new file mode 100644
index 0000000000..ebccf29735
--- /dev/null
+++ b/contrib/python/jsonschema/py2/jsonschema/tests/test_jsonschema_test_suite.py
@@ -0,0 +1,277 @@
+"""
+Test runner for the JSON Schema official test suite
+
+Tests comprehensive correctness of each draft's validator.
+
+See https://github.com/json-schema-org/JSON-Schema-Test-Suite for details.
+"""
+
+import sys
+import warnings
+
+from jsonschema import (
+ Draft3Validator,
+ Draft4Validator,
+ Draft6Validator,
+ Draft7Validator,
+ draft3_format_checker,
+ draft4_format_checker,
+ draft6_format_checker,
+ draft7_format_checker,
+)
+from jsonschema.tests._helpers import bug
+from jsonschema.tests._suite import Suite
+from jsonschema.validators import _DEPRECATED_DEFAULT_TYPES, create
+
+
+SUITE = Suite()
+DRAFT3 = SUITE.version(name="draft3")
+DRAFT4 = SUITE.version(name="draft4")
+DRAFT6 = SUITE.version(name="draft6")
+DRAFT7 = SUITE.version(name="draft7")
+
+
+def skip(message, **kwargs):
+ def skipper(test):
+ if all(value == getattr(test, attr) for attr, value in kwargs.items()):
+ return message
+ return skipper
+
+
+def missing_format(checker):
+ def missing_format(test):
+ schema = test.schema
+ if schema is True or schema is False or "format" not in schema:
+ return
+
+ if schema["format"] not in checker.checkers:
+ return "Format checker {0!r} not found.".format(schema["format"])
+ return missing_format
+
+
+is_narrow_build = sys.maxunicode == 2 ** 16 - 1
+if is_narrow_build: # pragma: no cover
+ message = "Not running surrogate Unicode case, this Python is narrow."
+
+ def narrow_unicode_build(test): # pragma: no cover
+ return skip(
+ message=message,
+ description="one supplementary Unicode code point is not long enough",
+ )(test) or skip(
+ message=message,
+ description="two supplementary Unicode code points is long enough",
+ )(test)
+else:
+ def narrow_unicode_build(test): # pragma: no cover
+ return
+
+
+TestDraft3 = DRAFT3.to_unittest_testcase(
+ DRAFT3.tests(),
+ DRAFT3.optional_tests_of(name="bignum"),
+ DRAFT3.optional_tests_of(name="format"),
+ DRAFT3.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft3Validator,
+ format_checker=draft3_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft3_format_checker)(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="format",
+ description="case-insensitive T and Z",
+ )(test)
+ ),
+)
+
+
+TestDraft4 = DRAFT4.to_unittest_testcase(
+ DRAFT4.tests(),
+ DRAFT4.optional_tests_of(name="bignum"),
+ DRAFT4.optional_tests_of(name="format"),
+ DRAFT4.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft4Validator,
+ format_checker=draft4_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft4_format_checker)(test)
+ or skip(
+ message=bug(),
+ subject="ref",
+ case_description="Recursive references between schemas",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description="Location-independent identifier",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with absolute URI"
+ ),
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with base URI change in subschema"
+ ),
+ )(test)
+ or skip(
+ message=bug(),
+ subject="refRemote",
+ case_description="base URI change - change folder in subschema",
+ )(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="format",
+ description="case-insensitive T and Z",
+ )(test)
+ ),
+)
+
+
+TestDraft6 = DRAFT6.to_unittest_testcase(
+ DRAFT6.tests(),
+ DRAFT6.optional_tests_of(name="bignum"),
+ DRAFT6.optional_tests_of(name="format"),
+ DRAFT6.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft6Validator,
+ format_checker=draft6_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft6_format_checker)(test)
+ or skip(
+ message=bug(),
+ subject="ref",
+ case_description="Recursive references between schemas",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description="Location-independent identifier",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with absolute URI"
+ ),
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with base URI change in subschema"
+ ),
+ )(test)
+ or skip(
+ message=bug(),
+ subject="refRemote",
+ case_description="base URI change - change folder in subschema",
+ )(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="format",
+ description="case-insensitive T and Z",
+ )(test)
+ ),
+)
+
+
+TestDraft7 = DRAFT7.to_unittest_testcase(
+ DRAFT7.tests(),
+ DRAFT7.format_tests(),
+ DRAFT7.optional_tests_of(name="bignum"),
+ DRAFT7.optional_tests_of(name="content"),
+ DRAFT7.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft7Validator,
+ format_checker=draft7_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft7_format_checker)(test)
+ or skip(
+ message=bug(),
+ subject="ref",
+ case_description="Recursive references between schemas",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description="Location-independent identifier",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with absolute URI"
+ ),
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with base URI change in subschema"
+ ),
+ )(test)
+ or skip(
+ message=bug(),
+ subject="refRemote",
+ case_description="base URI change - change folder in subschema",
+ )(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="date-time",
+ description="case-insensitive T and Z",
+ )(test)
+ or skip(
+ message=bug(593),
+ subject="content",
+ case_description=(
+ "validation of string-encoded content based on media type"
+ ),
+ )(test)
+ or skip(
+ message=bug(593),
+ subject="content",
+ case_description="validation of binary string-encoding",
+ )(test)
+ or skip(
+ message=bug(593),
+ subject="content",
+ case_description=(
+ "validation of binary-encoded media type documents"
+ ),
+ )(test)
+ ),
+)
+
+
+with warnings.catch_warnings():
+ warnings.simplefilter("ignore", DeprecationWarning)
+
+ TestDraft3LegacyTypeCheck = DRAFT3.to_unittest_testcase(
+ # Interestingly the any part couldn't really be done w/the old API.
+ (
+ (test for test in each if test.schema != {"type": "any"})
+ for each in DRAFT3.tests_of(name="type")
+ ),
+ name="TestDraft3LegacyTypeCheck",
+ Validator=create(
+ meta_schema=Draft3Validator.META_SCHEMA,
+ validators=Draft3Validator.VALIDATORS,
+ default_types=_DEPRECATED_DEFAULT_TYPES,
+ ),
+ )
+
+ TestDraft4LegacyTypeCheck = DRAFT4.to_unittest_testcase(
+ DRAFT4.tests_of(name="type"),
+ name="TestDraft4LegacyTypeCheck",
+ Validator=create(
+ meta_schema=Draft4Validator.META_SCHEMA,
+ validators=Draft4Validator.VALIDATORS,
+ default_types=_DEPRECATED_DEFAULT_TYPES,
+ ),
+ )
diff --git a/contrib/python/jsonschema/py2/patches/01-fix-tests.patch b/contrib/python/jsonschema/py2/patches/01-fix-tests.patch
new file mode 100644
index 0000000000..f35892f04f
--- /dev/null
+++ b/contrib/python/jsonschema/py2/patches/01-fix-tests.patch
@@ -0,0 +1,23 @@
+--- contrib/python/jsonschema/py2/jsonschema/tests/test_cli.py (index)
++++ contrib/python/jsonschema/py2/jsonschema/tests/test_cli.py (working tree)
+@@ -49,7 +49,7 @@ class TestParser(TestCase):
+ arguments = cli.parse_args(
+ [
+ "--validator",
+- "jsonschema.tests.test_cli.TestParser.FakeValidator",
++ "__tests__.test_cli.TestParser.FakeValidator", # XXX Arcadia
+ "--instance", self.instance_file,
+ self.schema_file,
+ ]
+@@ -141,11 +141,3 @@ class TestCLI(TestCase):
+ self.assertFalse(stdout.getvalue())
+ self.assertEqual(stderr.getvalue(), "1 - 9\t1 - 8\t2 - 7\t")
+ self.assertEqual(exit_code, 1)
+-
+- def test_version(self):
+- version = subprocess.check_output(
+- [sys.executable, "-m", "jsonschema", "--version"],
+- stderr=subprocess.STDOUT,
+- )
+- version = version.decode("utf-8").strip()
+- self.assertEqual(version, __version__)
diff --git a/contrib/python/jsonschema/py3/.yandex_meta/yamaker.yaml b/contrib/python/jsonschema/py3/.yandex_meta/yamaker.yaml
new file mode 100644
index 0000000000..da6fd45b32
--- /dev/null
+++ b/contrib/python/jsonschema/py3/.yandex_meta/yamaker.yaml
@@ -0,0 +1,4 @@
+exclude:
+ - json/*
+mark_as_tests:
+ - jsonschema/benchmarks/*
diff --git a/contrib/python/jsonschema/py3/jsonschema/benchmarks/__init__.py b/contrib/python/jsonschema/py3/jsonschema/benchmarks/__init__.py
new file mode 100644
index 0000000000..e3dcc68993
--- /dev/null
+++ b/contrib/python/jsonschema/py3/jsonschema/benchmarks/__init__.py
@@ -0,0 +1,5 @@
+"""
+Benchmarks for validation.
+
+This package is *not* public API.
+"""
diff --git a/contrib/python/jsonschema/py3/jsonschema/benchmarks/issue232.py b/contrib/python/jsonschema/py3/jsonschema/benchmarks/issue232.py
new file mode 100644
index 0000000000..65e3aedf79
--- /dev/null
+++ b/contrib/python/jsonschema/py3/jsonschema/benchmarks/issue232.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+"""
+A performance benchmark using the example from issue #232.
+
+See https://github.com/Julian/jsonschema/pull/232.
+"""
+from twisted.python.filepath import FilePath
+from pyperf import Runner
+from pyrsistent import m
+
+from jsonschema.tests._suite import Version
+import jsonschema
+
+
+issue232 = Version(
+ path=FilePath(__file__).sibling("issue232"),
+ remotes=m(),
+ name="issue232",
+)
+
+
+if __name__ == "__main__":
+ issue232.benchmark(
+ runner=Runner(),
+ Validator=jsonschema.Draft4Validator,
+ )
diff --git a/contrib/python/jsonschema/py3/jsonschema/benchmarks/json_schema_test_suite.py b/contrib/python/jsonschema/py3/jsonschema/benchmarks/json_schema_test_suite.py
new file mode 100644
index 0000000000..5add5051df
--- /dev/null
+++ b/contrib/python/jsonschema/py3/jsonschema/benchmarks/json_schema_test_suite.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+"""
+A performance benchmark using the official test suite.
+
+This benchmarks jsonschema using every valid example in the
+JSON-Schema-Test-Suite. It will take some time to complete.
+"""
+from pyperf import Runner
+
+from jsonschema.tests._suite import Suite
+
+
+if __name__ == "__main__":
+ Suite().benchmark(runner=Runner())
diff --git a/contrib/python/jsonschema/py3/jsonschema/tests/_suite.py b/contrib/python/jsonschema/py3/jsonschema/tests/_suite.py
new file mode 100644
index 0000000000..b68a7b668c
--- /dev/null
+++ b/contrib/python/jsonschema/py3/jsonschema/tests/_suite.py
@@ -0,0 +1,239 @@
+"""
+Python representations of the JSON Schema Test Suite tests.
+"""
+
+from functools import partial
+import json
+import os
+import re
+import subprocess
+import sys
+import unittest
+
+from twisted.python.filepath import FilePath
+import attr
+
+from jsonschema.compat import PY3
+from jsonschema.validators import validators
+import jsonschema
+
+
+def _find_suite():
+ root = os.environ.get("JSON_SCHEMA_TEST_SUITE")
+ if root is not None:
+ return FilePath(root)
+
+ root = FilePath(jsonschema.__file__).parent().sibling("json")
+ if not root.isdir(): # pragma: no cover
+ raise ValueError(
+ (
+ "Can't find the JSON-Schema-Test-Suite directory. "
+ "Set the 'JSON_SCHEMA_TEST_SUITE' environment "
+ "variable or run the tests from alongside a checkout "
+ "of the suite."
+ ),
+ )
+ return root
+
+
+@attr.s(hash=True)
+class Suite(object):
+
+ _root = attr.ib(default=attr.Factory(_find_suite))
+
+ def _remotes(self):
+ jsonschema_suite = self._root.descendant(["bin", "jsonschema_suite"])
+ remotes = subprocess.check_output(
+ [sys.executable, jsonschema_suite.path, "remotes"],
+ )
+ return {
+ "http://localhost:1234/" + name: schema
+ for name, schema in json.loads(remotes.decode("utf-8")).items()
+ }
+
+ def benchmark(self, runner): # pragma: no cover
+ for name in validators:
+ self.version(name=name).benchmark(runner=runner)
+
+ def version(self, name):
+ return Version(
+ name=name,
+ path=self._root.descendant(["tests", name]),
+ remotes=self._remotes(),
+ )
+
+
+@attr.s(hash=True)
+class Version(object):
+
+ _path = attr.ib()
+ _remotes = attr.ib()
+
+ name = attr.ib()
+
+ def benchmark(self, runner, **kwargs): # pragma: no cover
+ for suite in self.tests():
+ for test in suite:
+ runner.bench_func(
+ test.fully_qualified_name,
+ partial(test.validate_ignoring_errors, **kwargs),
+ )
+
+ def tests(self):
+ return (
+ test
+ for child in self._path.globChildren("*.json")
+ for test in self._tests_in(
+ subject=child.basename()[:-5],
+ path=child,
+ )
+ )
+
+ def format_tests(self):
+ path = self._path.descendant(["optional", "format"])
+ return (
+ test
+ for child in path.globChildren("*.json")
+ for test in self._tests_in(
+ subject=child.basename()[:-5],
+ path=child,
+ )
+ )
+
+ def tests_of(self, name):
+ return self._tests_in(
+ subject=name,
+ path=self._path.child(name + ".json"),
+ )
+
+ def optional_tests_of(self, name):
+ return self._tests_in(
+ subject=name,
+ path=self._path.descendant(["optional", name + ".json"]),
+ )
+
+ def to_unittest_testcase(self, *suites, **kwargs):
+ name = kwargs.pop("name", "Test" + self.name.title())
+ methods = {
+ test.method_name: test.to_unittest_method(**kwargs)
+ for suite in suites
+ for tests in suite
+ for test in tests
+ }
+ cls = type(name, (unittest.TestCase,), methods)
+
+ try:
+ cls.__module__ = _someone_save_us_the_module_of_the_caller()
+ except Exception: # pragma: no cover
+ # We're doing crazy things, so if they go wrong, like a function
+ # behaving differently on some other interpreter, just make them
+ # not happen.
+ pass
+
+ return cls
+
+ def _tests_in(self, subject, path):
+ for each in json.loads(path.getContent().decode("utf-8")):
+ yield (
+ _Test(
+ version=self,
+ subject=subject,
+ case_description=each["description"],
+ schema=each["schema"],
+ remotes=self._remotes,
+ **test
+ ) for test in each["tests"]
+ )
+
+
+@attr.s(hash=True, repr=False)
+class _Test(object):
+
+ version = attr.ib()
+
+ subject = attr.ib()
+ case_description = attr.ib()
+ description = attr.ib()
+
+ data = attr.ib()
+ schema = attr.ib(repr=False)
+
+ valid = attr.ib()
+
+ _remotes = attr.ib()
+
+ def __repr__(self): # pragma: no cover
+ return "<Test {}>".format(self.fully_qualified_name)
+
+ @property
+ def fully_qualified_name(self): # pragma: no cover
+ return " > ".join(
+ [
+ self.version.name,
+ self.subject,
+ self.case_description,
+ self.description,
+ ]
+ )
+
+ @property
+ def method_name(self):
+ delimiters = r"[\W\- ]+"
+ name = "test_%s_%s_%s" % (
+ re.sub(delimiters, "_", self.subject),
+ re.sub(delimiters, "_", self.case_description),
+ re.sub(delimiters, "_", self.description),
+ )
+
+ if not PY3: # pragma: no cover
+ name = name.encode("utf-8")
+ return name
+
+ def to_unittest_method(self, skip=lambda test: None, **kwargs):
+ if self.valid:
+ def fn(this):
+ self.validate(**kwargs)
+ else:
+ def fn(this):
+ with this.assertRaises(jsonschema.ValidationError):
+ self.validate(**kwargs)
+
+ fn.__name__ = self.method_name
+ reason = skip(self)
+ return unittest.skipIf(reason is not None, reason)(fn)
+
+ def validate(self, Validator, **kwargs):
+ resolver = jsonschema.RefResolver.from_schema(
+ schema=self.schema,
+ store=self._remotes,
+ id_of=Validator.ID_OF,
+ )
+ jsonschema.validate(
+ instance=self.data,
+ schema=self.schema,
+ cls=Validator,
+ resolver=resolver,
+ **kwargs
+ )
+
+ def validate_ignoring_errors(self, Validator): # pragma: no cover
+ try:
+ self.validate(Validator=Validator)
+ except jsonschema.ValidationError:
+ pass
+
+
+def _someone_save_us_the_module_of_the_caller():
+ """
+ The FQON of the module 2nd stack frames up from here.
+
+ This is intended to allow us to dynamicallly return test case classes that
+ are indistinguishable from being defined in the module that wants them.
+
+ Otherwise, trial will mis-print the FQON, and copy pasting it won't re-run
+ the class that really is running.
+
+ Save us all, this is all so so so so so terrible.
+ """
+
+ return sys._getframe(2).f_globals["__name__"]
diff --git a/contrib/python/jsonschema/py3/jsonschema/tests/test_jsonschema_test_suite.py b/contrib/python/jsonschema/py3/jsonschema/tests/test_jsonschema_test_suite.py
new file mode 100644
index 0000000000..ebccf29735
--- /dev/null
+++ b/contrib/python/jsonschema/py3/jsonschema/tests/test_jsonschema_test_suite.py
@@ -0,0 +1,277 @@
+"""
+Test runner for the JSON Schema official test suite
+
+Tests comprehensive correctness of each draft's validator.
+
+See https://github.com/json-schema-org/JSON-Schema-Test-Suite for details.
+"""
+
+import sys
+import warnings
+
+from jsonschema import (
+ Draft3Validator,
+ Draft4Validator,
+ Draft6Validator,
+ Draft7Validator,
+ draft3_format_checker,
+ draft4_format_checker,
+ draft6_format_checker,
+ draft7_format_checker,
+)
+from jsonschema.tests._helpers import bug
+from jsonschema.tests._suite import Suite
+from jsonschema.validators import _DEPRECATED_DEFAULT_TYPES, create
+
+
+SUITE = Suite()
+DRAFT3 = SUITE.version(name="draft3")
+DRAFT4 = SUITE.version(name="draft4")
+DRAFT6 = SUITE.version(name="draft6")
+DRAFT7 = SUITE.version(name="draft7")
+
+
+def skip(message, **kwargs):
+ def skipper(test):
+ if all(value == getattr(test, attr) for attr, value in kwargs.items()):
+ return message
+ return skipper
+
+
+def missing_format(checker):
+ def missing_format(test):
+ schema = test.schema
+ if schema is True or schema is False or "format" not in schema:
+ return
+
+ if schema["format"] not in checker.checkers:
+ return "Format checker {0!r} not found.".format(schema["format"])
+ return missing_format
+
+
+is_narrow_build = sys.maxunicode == 2 ** 16 - 1
+if is_narrow_build: # pragma: no cover
+ message = "Not running surrogate Unicode case, this Python is narrow."
+
+ def narrow_unicode_build(test): # pragma: no cover
+ return skip(
+ message=message,
+ description="one supplementary Unicode code point is not long enough",
+ )(test) or skip(
+ message=message,
+ description="two supplementary Unicode code points is long enough",
+ )(test)
+else:
+ def narrow_unicode_build(test): # pragma: no cover
+ return
+
+
+TestDraft3 = DRAFT3.to_unittest_testcase(
+ DRAFT3.tests(),
+ DRAFT3.optional_tests_of(name="bignum"),
+ DRAFT3.optional_tests_of(name="format"),
+ DRAFT3.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft3Validator,
+ format_checker=draft3_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft3_format_checker)(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="format",
+ description="case-insensitive T and Z",
+ )(test)
+ ),
+)
+
+
+TestDraft4 = DRAFT4.to_unittest_testcase(
+ DRAFT4.tests(),
+ DRAFT4.optional_tests_of(name="bignum"),
+ DRAFT4.optional_tests_of(name="format"),
+ DRAFT4.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft4Validator,
+ format_checker=draft4_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft4_format_checker)(test)
+ or skip(
+ message=bug(),
+ subject="ref",
+ case_description="Recursive references between schemas",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description="Location-independent identifier",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with absolute URI"
+ ),
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with base URI change in subschema"
+ ),
+ )(test)
+ or skip(
+ message=bug(),
+ subject="refRemote",
+ case_description="base URI change - change folder in subschema",
+ )(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="format",
+ description="case-insensitive T and Z",
+ )(test)
+ ),
+)
+
+
+TestDraft6 = DRAFT6.to_unittest_testcase(
+ DRAFT6.tests(),
+ DRAFT6.optional_tests_of(name="bignum"),
+ DRAFT6.optional_tests_of(name="format"),
+ DRAFT6.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft6Validator,
+ format_checker=draft6_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft6_format_checker)(test)
+ or skip(
+ message=bug(),
+ subject="ref",
+ case_description="Recursive references between schemas",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description="Location-independent identifier",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with absolute URI"
+ ),
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with base URI change in subschema"
+ ),
+ )(test)
+ or skip(
+ message=bug(),
+ subject="refRemote",
+ case_description="base URI change - change folder in subschema",
+ )(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="format",
+ description="case-insensitive T and Z",
+ )(test)
+ ),
+)
+
+
+TestDraft7 = DRAFT7.to_unittest_testcase(
+ DRAFT7.tests(),
+ DRAFT7.format_tests(),
+ DRAFT7.optional_tests_of(name="bignum"),
+ DRAFT7.optional_tests_of(name="content"),
+ DRAFT7.optional_tests_of(name="zeroTerminatedFloats"),
+ Validator=Draft7Validator,
+ format_checker=draft7_format_checker,
+ skip=lambda test: (
+ narrow_unicode_build(test)
+ or missing_format(draft7_format_checker)(test)
+ or skip(
+ message=bug(),
+ subject="ref",
+ case_description="Recursive references between schemas",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description="Location-independent identifier",
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with absolute URI"
+ ),
+ )(test)
+ or skip(
+ message=bug(371),
+ subject="ref",
+ case_description=(
+ "Location-independent identifier with base URI change in subschema"
+ ),
+ )(test)
+ or skip(
+ message=bug(),
+ subject="refRemote",
+ case_description="base URI change - change folder in subschema",
+ )(test)
+ or skip(
+ message="Upstream bug in strict_rfc3339",
+ subject="date-time",
+ description="case-insensitive T and Z",
+ )(test)
+ or skip(
+ message=bug(593),
+ subject="content",
+ case_description=(
+ "validation of string-encoded content based on media type"
+ ),
+ )(test)
+ or skip(
+ message=bug(593),
+ subject="content",
+ case_description="validation of binary string-encoding",
+ )(test)
+ or skip(
+ message=bug(593),
+ subject="content",
+ case_description=(
+ "validation of binary-encoded media type documents"
+ ),
+ )(test)
+ ),
+)
+
+
+with warnings.catch_warnings():
+ warnings.simplefilter("ignore", DeprecationWarning)
+
+ TestDraft3LegacyTypeCheck = DRAFT3.to_unittest_testcase(
+ # Interestingly the any part couldn't really be done w/the old API.
+ (
+ (test for test in each if test.schema != {"type": "any"})
+ for each in DRAFT3.tests_of(name="type")
+ ),
+ name="TestDraft3LegacyTypeCheck",
+ Validator=create(
+ meta_schema=Draft3Validator.META_SCHEMA,
+ validators=Draft3Validator.VALIDATORS,
+ default_types=_DEPRECATED_DEFAULT_TYPES,
+ ),
+ )
+
+ TestDraft4LegacyTypeCheck = DRAFT4.to_unittest_testcase(
+ DRAFT4.tests_of(name="type"),
+ name="TestDraft4LegacyTypeCheck",
+ Validator=create(
+ meta_schema=Draft4Validator.META_SCHEMA,
+ validators=Draft4Validator.VALIDATORS,
+ default_types=_DEPRECATED_DEFAULT_TYPES,
+ ),
+ )
diff --git a/contrib/python/jsonschema/py3/patches/01-fix-tests.patch b/contrib/python/jsonschema/py3/patches/01-fix-tests.patch
new file mode 100644
index 0000000000..4a23eff69a
--- /dev/null
+++ b/contrib/python/jsonschema/py3/patches/01-fix-tests.patch
@@ -0,0 +1,23 @@
+--- contrib/python/jsonschema/py3/jsonschema/tests/test_cli.py (index)
++++ contrib/python/jsonschema/py3/jsonschema/tests/test_cli.py (working tree)
+@@ -49,7 +49,7 @@ class TestParser(TestCase):
+ arguments = cli.parse_args(
+ [
+ "--validator",
+- "jsonschema.tests.test_cli.TestParser.FakeValidator",
++ "__tests__.test_cli.TestParser.FakeValidator", # XXX Arcadia
+ "--instance", self.instance_file,
+ self.schema_file,
+ ]
+@@ -141,11 +141,3 @@ class TestCLI(TestCase):
+ self.assertFalse(stdout.getvalue())
+ self.assertEqual(stderr.getvalue(), "1 - 9\t1 - 8\t2 - 7\t")
+ self.assertEqual(exit_code, 1)
+-
+- def test_version(self):
+- version = subprocess.check_output(
+- [sys.executable, "-m", "jsonschema", "--version"],
+- stderr=subprocess.STDOUT,
+- )
+- version = version.decode("utf-8").strip()
+- self.assertEqual(version, __version__)
diff --git a/contrib/python/jsonschema/py3/patches/02-support-python-3.12.patch b/contrib/python/jsonschema/py3/patches/02-support-python-3.12.patch
new file mode 100644
index 0000000000..691c43b437
--- /dev/null
+++ b/contrib/python/jsonschema/py3/patches/02-support-python-3.12.patch
@@ -0,0 +1,8 @@
+--- contrib/python/jsonschema/py3/jsonschema/tests/test_validators.py (8114480972e2ddb6aa7203d22024fbc36b1b6fec)
++++ contrib/python/jsonschema/py3/jsonschema/tests/test_validators.py (462a1dacdcd6f4eb462650be556c7378a1dc9e4a)
+@@ -1528 +1528 @@ class TestValidate(SynchronousTestCase):
+- self.assertRegexpMatches(
++ self.assertRegex(
+@@ -1536 +1536 @@ class TestValidate(SynchronousTestCase):
+- self.assertRegexpMatches(
++ self.assertRegex(