JSONSchemata 0.0.0.dev0__tar.gz → 0.0.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: JSONSchemata
3
- Version: 0.0.0.dev0
3
+ Version: 0.0.0.dev1
4
4
  Requires-Python: >=3.10
5
5
  License-File: LICENSE
6
6
  Requires-Dist: jsonschema<5,>=4.21.0
7
- Requires-Dist: referencing==0.35.1
7
+ Requires-Dist: referencing>=0.35.1
@@ -17,10 +17,10 @@ namespaces = true
17
17
  # ----------------------------------------- Project Metadata -------------------------------------
18
18
  #
19
19
  [project]
20
- version = "0.0.0.dev0"
20
+ version = "0.0.0.dev1"
21
21
  name = "JSONSchemata"
22
22
  dependencies = [
23
23
  "jsonschema >= 4.21.0, < 5",
24
- "referencing == 0.35.1",
24
+ "referencing >= 0.35.1",
25
25
  ]
26
26
  requires-python = ">=3.10"
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: JSONSchemata
3
- Version: 0.0.0.dev0
3
+ Version: 0.0.0.dev1
4
4
  Requires-Python: >=3.10
5
5
  License-File: LICENSE
6
6
  Requires-Dist: jsonschema<5,>=4.21.0
7
- Requires-Dist: referencing==0.35.1
7
+ Requires-Dist: referencing>=0.35.1
@@ -6,4 +6,6 @@ src/JSONSchemata.egg-info/dependency_links.txt
6
6
  src/JSONSchemata.egg-info/not-zip-safe
7
7
  src/JSONSchemata.egg-info/requires.txt
8
8
  src/JSONSchemata.egg-info/top_level.txt
9
- src/jsonschemata/__init__.py
9
+ src/jsonschemata/__init__.py
10
+ src/jsonschemata/edit.py
11
+ src/jsonschemata/registry.py
@@ -1,2 +1,2 @@
1
1
  jsonschema<5,>=4.21.0
2
- referencing==0.35.1
2
+ referencing>=0.35.1
@@ -0,0 +1 @@
1
+ from jsonschemata import edit, registry
@@ -0,0 +1,27 @@
1
+ def required_last(schema: dict) -> dict:
2
+ """Modify JSON schema to recursively put all 'required' fields at the end of the schema.
3
+
4
+ This is done because otherwise the 'required' fields
5
+ are checked by jsonschema before filling the defaults,
6
+ which can cause the validation to fail.
7
+
8
+ Returns
9
+ -------
10
+ dict
11
+ Modified schema.
12
+ Note that the input schema is modified in-place,
13
+ so the return value is a reference to the (now modified) input schema.
14
+ """
15
+ if "required" in schema:
16
+ schema["required"] = schema.pop("required")
17
+ for key in ["anyOf", "allOf", "oneOf", "prefixItems"]:
18
+ if key in schema:
19
+ for subschema in schema[key]:
20
+ required_last(subschema)
21
+ for key in ["if", "then", "else", "not", "items", "additionalProperties"]:
22
+ if key in schema and isinstance(schema[key], dict):
23
+ required_last(schema[key])
24
+ if "properties" in schema and isinstance(schema["properties"], dict):
25
+ for subschema in schema["properties"].values():
26
+ required_last(subschema)
27
+ return schema
@@ -0,0 +1,100 @@
1
+ from typing import Callable as _Callable
2
+ import referencing as _referencing
3
+ from referencing import jsonschema as _ref_jsonschema, retrieval as _ref_retrieval
4
+ import pkgdata as _pkgdata
5
+ import pyserials as _ps
6
+ import pylinks as _pl
7
+
8
+ from jsonschemata import edit as _edit
9
+
10
+
11
+ def make(
12
+ dynamic: bool = False,
13
+ crawl: bool = True,
14
+ add_resources: list[dict | _referencing.Resource | tuple[str, dict | _referencing.Resource]] | None = None,
15
+ add_resources_default_spec: _referencing.Specification = _ref_jsonschema.DRAFT202012,
16
+ retrieval_func: _Callable[[str], str | _referencing.Resource] = None,
17
+ ) -> _referencing.Registry:
18
+ """Create a registry of all JSON schemas.
19
+
20
+ Parameters
21
+ ----------
22
+ dynamic : bool, default: False
23
+ If True, any reference that is not found in the registry will be
24
+ [dynamically retrieved](https://referencing.readthedocs.io/en/stable/intro/#dynamically-retrieving-resources)
25
+ and [cached](https://referencing.readthedocs.io/en/stable/intro/#caching).
26
+ The retrieval works as follows:
27
+ If the reference URI starts with "http" or "https", the URI is fetched using an HTTP GET request.
28
+ Otherwise, the URI is assumed to be a local filepath,
29
+ which can be either absolute or relative to the current working directory.
30
+ You can also provide a custom retrieval function using the `retrieval_func` parameter.
31
+ crawl : bool, default: True
32
+ Pre [crawl](https://referencing.readthedocs.io/en/stable/api/#referencing.Registry.crawl)
33
+ all resources so that the registry is
34
+ [fully ready](https://referencing.readthedocs.io/en/stable/schema-packages/).
35
+ add_resources: list[dict | referencing.Resource | tuple[str, dict | referencing.Resource]] | None, default: None
36
+ A list of additional resources to add to the registry. Each resource can be a dictionary or
37
+ a [`referencing.Resource`](https://referencing.readthedocs.io/en/stable/api/#referencing.Resource)
38
+ object. If a resource does not have an "$id",
39
+ the ID must be provided along with the resource as a tuple of (ID, resource).
40
+ add_resources_default_spec: referencing.Specification, default: referencing.jsonschema.DRAFT202012
41
+ The default specification to use when creating an additional resource from a dictionary.
42
+ retrieval_func: Callable[[str], str | referencing.Resource], optional
43
+ A custom retrieval function to use when `dynamic` is True.
44
+ The function should take a URI as input and return the reference schema.
45
+ If you want the retrieval function to also cache the retrieved references,
46
+ the function must be decorated with the
47
+ [`@referencing.retrieval.to_cached_resource`](https://referencing.readthedocs.io/en/stable/api/#referencing.retrieval.to_cached_resource)
48
+ decorator, in which case the function must return the reference schema as a JSON string
49
+ (cf. [Referencing Docs](https://referencing.readthedocs.io/en/stable/intro/#caching)).
50
+ If the decorator is not used, the function must return the schema as a `referencing.Resource` instead.
51
+ Note that this retrieval function will only be used when `dynamic` is set to `True`.
52
+ Returns
53
+ -------
54
+ referencing.Registry
55
+ A [`referencing.Registry`](https://referencing.readthedocs.io/en/stable/api/#referencing.Registry)
56
+ object containing all resources.
57
+ """
58
+
59
+ @_ref_retrieval.to_cached_resource()
60
+ def retrieve_url(uri: str) -> str:
61
+ if uri.startswith(("http://", "https://")):
62
+ return _pl.http.request(url=uri, response_type="str")
63
+ return _ps.write.to_json_string(_ps.read.from_file(path=uri, toml_as_dict=True), sort_keys=False)
64
+
65
+ schema_dir_path = _pkgdata.get_package_path_from_caller(top_level=True) / "_data"
66
+ resources = []
67
+ for schema_filepath in schema_dir_path.glob("**/*.yaml"):
68
+ schema_dict = _ps.read.yaml_from_file(path=schema_filepath)
69
+ _edit.required_last(schema_dict)
70
+ schema = _referencing.Resource.from_contents(
71
+ schema_dict, default_specification=_ref_jsonschema.DRAFT202012
72
+ )
73
+ resources.append(schema)
74
+
75
+ id_resources: list[tuple[str, _referencing.Resource]] = []
76
+ for add_resource in add_resources or []:
77
+ resource_id = None
78
+ if isinstance(add_resource, dict):
79
+ add_resource = _referencing.Resource.from_contents(
80
+ add_resource, default_specification=add_resources_default_spec
81
+ )
82
+ elif isinstance(add_resource, tuple):
83
+ resource_id, resource_dict = add_resource
84
+ add_resource = _referencing.Resource.from_contents(
85
+ resource_dict, default_specification=add_resources_default_spec,
86
+ )
87
+ if resource_id:
88
+ id_resources.append((resource_id, add_resource))
89
+ else:
90
+ resources.append(add_resource)
91
+
92
+ registry = _referencing.Registry(
93
+ retrieve=retrieval_func or retrieve_url
94
+ ) if dynamic else _referencing.Registry()
95
+ registry = resources @ registry
96
+ if id_resources:
97
+ registry = registry.with_resources(id_resources)
98
+ if crawl:
99
+ registry.crawl()
100
+ return registry
File without changes