aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/jsonschema/_utils.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/jsonschema/_utils.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-4a52a71956a8d46fcb7294ac71734504bb09bcc2.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/jsonschema/_utils.py')
-rw-r--r--.venv/lib/python3.12/site-packages/jsonschema/_utils.py351
1 files changed, 351 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/jsonschema/_utils.py b/.venv/lib/python3.12/site-packages/jsonschema/_utils.py
new file mode 100644
index 00000000..54d28c04
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/jsonschema/_utils.py
@@ -0,0 +1,351 @@
+from collections.abc import Mapping, MutableMapping, Sequence
+from urllib.parse import urlsplit
+import itertools
+import re
+
+
+class URIDict(MutableMapping):
+ """
+ Dictionary which uses normalized URIs as keys.
+ """
+
+ def normalize(self, uri):
+ return urlsplit(uri).geturl()
+
+ def __init__(self, *args, **kwargs):
+ self.store = dict()
+ self.store.update(*args, **kwargs)
+
+ def __getitem__(self, uri):
+ return self.store[self.normalize(uri)]
+
+ def __setitem__(self, uri, value):
+ self.store[self.normalize(uri)] = value
+
+ def __delitem__(self, uri):
+ del self.store[self.normalize(uri)]
+
+ def __iter__(self):
+ return iter(self.store)
+
+ def __len__(self): # pragma: no cover -- untested, but to be removed
+ return len(self.store)
+
+ def __repr__(self): # pragma: no cover -- untested, but to be removed
+ return repr(self.store)
+
+
+class Unset:
+ """
+ An as-of-yet unset attribute or unprovided default parameter.
+ """
+
+ def __repr__(self): # pragma: no cover
+ return "<unset>"
+
+
+def format_as_index(container, indices):
+ """
+ Construct a single string containing indexing operations for the indices.
+
+ For example for a container ``bar``, [1, 2, "foo"] -> bar[1][2]["foo"]
+
+ Arguments:
+
+ container (str):
+
+ A word to use for the thing being indexed
+
+ indices (sequence):
+
+ The indices to format.
+
+ """
+ if not indices:
+ return container
+ return f"{container}[{']['.join(repr(index) for index in indices)}]"
+
+
+def find_additional_properties(instance, schema):
+ """
+ Return the set of additional properties for the given ``instance``.
+
+ Weeds out properties that should have been validated by ``properties`` and
+ / or ``patternProperties``.
+
+ Assumes ``instance`` is dict-like already.
+ """
+ properties = schema.get("properties", {})
+ patterns = "|".join(schema.get("patternProperties", {}))
+ for property in instance:
+ if property not in properties:
+ if patterns and re.search(patterns, property):
+ continue
+ yield property
+
+
+def extras_msg(extras):
+ """
+ Create an error message for extra items or properties.
+ """
+ verb = "was" if len(extras) == 1 else "were"
+ return ", ".join(repr(extra) for extra in extras), verb
+
+
+def ensure_list(thing):
+ """
+ Wrap ``thing`` in a list if it's a single str.
+
+ Otherwise, return it unchanged.
+ """
+ if isinstance(thing, str):
+ return [thing]
+ return thing
+
+
+def _mapping_equal(one, two):
+ """
+ Check if two mappings are equal using the semantics of `equal`.
+ """
+ if len(one) != len(two):
+ return False
+ return all(
+ key in two and equal(value, two[key])
+ for key, value in one.items()
+ )
+
+
+def _sequence_equal(one, two):
+ """
+ Check if two sequences are equal using the semantics of `equal`.
+ """
+ if len(one) != len(two):
+ return False
+ return all(equal(i, j) for i, j in zip(one, two))
+
+
+def equal(one, two):
+ """
+ Check if two things are equal evading some Python type hierarchy semantics.
+
+ Specifically in JSON Schema, evade `bool` inheriting from `int`,
+ recursing into sequences to do the same.
+ """
+ if one is two:
+ return True
+ if isinstance(one, str) or isinstance(two, str):
+ return one == two
+ if isinstance(one, Sequence) and isinstance(two, Sequence):
+ return _sequence_equal(one, two)
+ if isinstance(one, Mapping) and isinstance(two, Mapping):
+ return _mapping_equal(one, two)
+ return unbool(one) == unbool(two)
+
+
+def unbool(element, true=object(), false=object()):
+ """
+ A hack to make True and 1 and False and 0 unique for ``uniq``.
+ """
+ if element is True:
+ return true
+ elif element is False:
+ return false
+ return element
+
+
+def uniq(container):
+ """
+ Check if all of a container's elements are unique.
+
+ Tries to rely on the container being recursively sortable, or otherwise
+ falls back on (slow) brute force.
+ """
+ try:
+ sort = sorted(unbool(i) for i in container)
+ sliced = itertools.islice(sort, 1, None)
+
+ for i, j in zip(sort, sliced):
+ if equal(i, j):
+ return False
+
+ except (NotImplementedError, TypeError):
+ seen = []
+ for e in container:
+ e = unbool(e)
+
+ for i in seen:
+ if equal(i, e):
+ return False
+
+ seen.append(e)
+ return True
+
+
+def find_evaluated_item_indexes_by_schema(validator, instance, schema):
+ """
+ Get all indexes of items that get evaluated under the current schema.
+
+ Covers all keywords related to unevaluatedItems: items, prefixItems, if,
+ then, else, contains, unevaluatedItems, allOf, oneOf, anyOf
+ """
+ if validator.is_type(schema, "boolean"):
+ return []
+ evaluated_indexes = []
+
+ if "items" in schema:
+ return list(range(len(instance)))
+
+ ref = schema.get("$ref")
+ if ref is not None:
+ resolved = validator._resolver.lookup(ref)
+ evaluated_indexes.extend(
+ find_evaluated_item_indexes_by_schema(
+ validator.evolve(
+ schema=resolved.contents,
+ _resolver=resolved.resolver,
+ ),
+ instance,
+ resolved.contents,
+ ),
+ )
+
+ dynamicRef = schema.get("$dynamicRef")
+ if dynamicRef is not None:
+ resolved = validator._resolver.lookup(dynamicRef)
+ evaluated_indexes.extend(
+ find_evaluated_item_indexes_by_schema(
+ validator.evolve(
+ schema=resolved.contents,
+ _resolver=resolved.resolver,
+ ),
+ instance,
+ resolved.contents,
+ ),
+ )
+
+ if "prefixItems" in schema:
+ evaluated_indexes += list(range(len(schema["prefixItems"])))
+
+ if "if" in schema:
+ if validator.evolve(schema=schema["if"]).is_valid(instance):
+ evaluated_indexes += find_evaluated_item_indexes_by_schema(
+ validator, instance, schema["if"],
+ )
+ if "then" in schema:
+ evaluated_indexes += find_evaluated_item_indexes_by_schema(
+ validator, instance, schema["then"],
+ )
+ elif "else" in schema:
+ evaluated_indexes += find_evaluated_item_indexes_by_schema(
+ validator, instance, schema["else"],
+ )
+
+ for keyword in ["contains", "unevaluatedItems"]:
+ if keyword in schema:
+ for k, v in enumerate(instance):
+ if validator.evolve(schema=schema[keyword]).is_valid(v):
+ evaluated_indexes.append(k)
+
+ for keyword in ["allOf", "oneOf", "anyOf"]:
+ if keyword in schema:
+ for subschema in schema[keyword]:
+ errs = next(validator.descend(instance, subschema), None)
+ if errs is None:
+ evaluated_indexes += find_evaluated_item_indexes_by_schema(
+ validator, instance, subschema,
+ )
+
+ return evaluated_indexes
+
+
+def find_evaluated_property_keys_by_schema(validator, instance, schema):
+ """
+ Get all keys of items that get evaluated under the current schema.
+
+ Covers all keywords related to unevaluatedProperties: properties,
+ additionalProperties, unevaluatedProperties, patternProperties,
+ dependentSchemas, allOf, oneOf, anyOf, if, then, else
+ """
+ if validator.is_type(schema, "boolean"):
+ return []
+ evaluated_keys = []
+
+ ref = schema.get("$ref")
+ if ref is not None:
+ resolved = validator._resolver.lookup(ref)
+ evaluated_keys.extend(
+ find_evaluated_property_keys_by_schema(
+ validator.evolve(
+ schema=resolved.contents,
+ _resolver=resolved.resolver,
+ ),
+ instance,
+ resolved.contents,
+ ),
+ )
+
+ dynamicRef = schema.get("$dynamicRef")
+ if dynamicRef is not None:
+ resolved = validator._resolver.lookup(dynamicRef)
+ evaluated_keys.extend(
+ find_evaluated_property_keys_by_schema(
+ validator.evolve(
+ schema=resolved.contents,
+ _resolver=resolved.resolver,
+ ),
+ instance,
+ resolved.contents,
+ ),
+ )
+
+ for keyword in [
+ "properties", "additionalProperties", "unevaluatedProperties",
+ ]:
+ if keyword in schema:
+ schema_value = schema[keyword]
+ if validator.is_type(schema_value, "boolean") and schema_value:
+ evaluated_keys += instance.keys()
+
+ elif validator.is_type(schema_value, "object"):
+ for property in schema_value:
+ if property in instance:
+ evaluated_keys.append(property)
+
+ if "patternProperties" in schema:
+ for property in instance:
+ for pattern in schema["patternProperties"]:
+ if re.search(pattern, property):
+ evaluated_keys.append(property)
+
+ if "dependentSchemas" in schema:
+ for property, subschema in schema["dependentSchemas"].items():
+ if property not in instance:
+ continue
+ evaluated_keys += find_evaluated_property_keys_by_schema(
+ validator, instance, subschema,
+ )
+
+ for keyword in ["allOf", "oneOf", "anyOf"]:
+ if keyword in schema:
+ for subschema in schema[keyword]:
+ errs = next(validator.descend(instance, subschema), None)
+ if errs is None:
+ evaluated_keys += find_evaluated_property_keys_by_schema(
+ validator, instance, subschema,
+ )
+
+ if "if" in schema:
+ if validator.evolve(schema=schema["if"]).is_valid(instance):
+ evaluated_keys += find_evaluated_property_keys_by_schema(
+ validator, instance, schema["if"],
+ )
+ if "then" in schema:
+ evaluated_keys += find_evaluated_property_keys_by_schema(
+ validator, instance, schema["then"],
+ )
+ elif "else" in schema:
+ evaluated_keys += find_evaluated_property_keys_by_schema(
+ validator, instance, schema["else"],
+ )
+
+ return evaluated_keys