Skip to content

Commit

Permalink
Support patternProperties in regex variants
Browse files Browse the repository at this point in the history
  • Loading branch information
sirosen committed Dec 23, 2024
1 parent 5cf5ae1 commit 6d99fd8
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 8 deletions.
9 changes: 2 additions & 7 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ Example usage:
~~~~~~~~~~~~~~~~~~

Set a mode for handling of the ``"regex"`` value for ``"format"`` and the mode
for ``"pattern"`` interpretation. The modes are as follows:
for ``"pattern"`` and ``"patternProperties"`` interpretation.
The modes are as follows:

.. list-table:: Regex Options
:widths: 15 30
Expand All @@ -202,12 +203,6 @@ for ``"pattern"`` interpretation. The modes are as follows:
* - python
- Use Python regex syntax.

.. note::

This only controls the regex mode used for ``format`` and ``pattern``.
``patternProperties`` is not currently controlled, and always uses the
Python engine.

Other Options
--------------

Expand Down
73 changes: 73 additions & 0 deletions src/check_jsonschema/regex_variants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ def pattern_keyword(
self, validator: t.Any, pattern: str, instance: str, schema: t.Any
) -> t.Iterator[jsonschema.ValidationError]: ...

def patternProperties_keyword(
self,
validator: t.Any,
patternProperties: dict[str, t.Any],
instance: dict[str, t.Any],
schema: t.Any,
) -> t.Iterator[jsonschema.ValidationError]: ...


class RegexImplementation:
"""
Expand All @@ -40,6 +48,9 @@ def __init__(self, variant: RegexVariantName) -> None:

self.check_format = self._real_implementation.check_format
self.pattern_keyword = self._real_implementation.pattern_keyword
self.patternProperties_keyword = (
self._real_implementation.patternProperties_keyword
)


class _UnicodeRegressImplementation:
Expand All @@ -65,6 +76,27 @@ def pattern_keyword(
if not regress_pattern.find(instance):
yield jsonschema.ValidationError(f"{instance!r} does not match {pattern!r}")

def patternProperties_keyword(
self,
validator: t.Any,
patternProperties: dict[str, t.Any],
instance: dict[str, t.Any],
schema: t.Any,
) -> t.Iterator[jsonschema.ValidationError]:
if not validator.is_type(instance, "object"):
return

for pattern, subschema in patternProperties.items():
regress_pattern = regress.Regex(pattern, flags="u")
for k, v in instance.items():
if regress_pattern.find(k):
yield from validator.descend(
v,
subschema,
path=k,
schema_path=pattern,
)


class _NonunicodeRegressImplementation:
def check_format(self, instance: t.Any) -> bool:
Expand All @@ -89,6 +121,27 @@ def pattern_keyword(
if not regress_pattern.find(instance):
yield jsonschema.ValidationError(f"{instance!r} does not match {pattern!r}")

def patternProperties_keyword(
self,
validator: t.Any,
patternProperties: dict[str, t.Any],
instance: dict[str, t.Any],
schema: t.Any,
) -> t.Iterator[jsonschema.ValidationError]:
if not validator.is_type(instance, "object"):
return

for pattern, subschema in patternProperties.items():
regress_pattern = regress.Regex(pattern)
for k, v in instance.items():
if regress_pattern.find(k):
yield from validator.descend(
v,
subschema,
path=k,
schema_path=pattern,
)


class _PythonImplementation:
def check_format(self, instance: t.Any) -> bool:
Expand All @@ -112,3 +165,23 @@ def pattern_keyword(
yield jsonschema.ValidationError(f"pattern {pattern!r} failed to compile")
if not re_pattern.search(instance):
yield jsonschema.ValidationError(f"{instance!r} does not match {pattern!r}")

def patternProperties_keyword(
self,
validator: t.Any,
patternProperties: dict[str, t.Any],
instance: dict[str, t.Any],
schema: t.Any,
) -> t.Iterator[jsonschema.ValidationError]:
if not validator.is_type(instance, "object"):
return

for pattern, subschema in patternProperties.items():
for k, v in instance.items():
if re.search(pattern, k):
yield from validator.descend(
v,
subschema,
path=k,
schema_path=pattern,
)
5 changes: 4 additions & 1 deletion src/check_jsonschema/schema_loader/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ def _extend_with_pattern_implementation(
) -> type[jsonschema.Validator]:
return jsonschema.validators.extend(
validator_class,
{"pattern": regex_impl.pattern_keyword},
{
"pattern": regex_impl.pattern_keyword,
"patternProperties": regex_impl.patternProperties_keyword,
},
)


Expand Down

0 comments on commit 6d99fd8

Please sign in to comment.