ogc-na 0.3.44__py3-none-any.whl → 0.3.46__py3-none-any.whl
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.
Potentially problematic release.
This version of ogc-na might be problematic. Click here for more details.
- ogc/na/_version.py +2 -2
- ogc/na/annotate_schema.py +41 -34
- {ogc_na-0.3.44.dist-info → ogc_na-0.3.46.dist-info}/METADATA +2 -1
- {ogc_na-0.3.44.dist-info → ogc_na-0.3.46.dist-info}/RECORD +6 -6
- {ogc_na-0.3.44.dist-info → ogc_na-0.3.46.dist-info}/WHEEL +0 -0
- {ogc_na-0.3.44.dist-info → ogc_na-0.3.46.dist-info}/top_level.txt +0 -0
ogc/na/_version.py
CHANGED
ogc/na/annotate_schema.py
CHANGED
|
@@ -122,12 +122,12 @@ import json
|
|
|
122
122
|
import logging
|
|
123
123
|
import re
|
|
124
124
|
import sys
|
|
125
|
-
from collections import deque
|
|
126
125
|
from operator import attrgetter
|
|
127
126
|
from pathlib import Path
|
|
128
127
|
from typing import Any, AnyStr, Callable, Sequence, Iterable
|
|
129
128
|
from urllib.parse import urlparse, urljoin
|
|
130
129
|
|
|
130
|
+
import jsonpointer
|
|
131
131
|
import jsonschema
|
|
132
132
|
import requests_cache
|
|
133
133
|
|
|
@@ -147,6 +147,8 @@ ANNOTATION_IGNORE_EXPAND = [ANNOTATION_CONTEXT, ANNOTATION_EXTRA_TERMS, ANNOTATI
|
|
|
147
147
|
|
|
148
148
|
CURIE_TERMS = '@id', '@type', '@index'
|
|
149
149
|
|
|
150
|
+
UNDEFINED = object()
|
|
151
|
+
|
|
150
152
|
context_term_cache = LRUCache(maxsize=20)
|
|
151
153
|
requests_session = requests_cache.CachedSession('ogc.na.annotate_schema', backend='memory', expire_after=180)
|
|
152
154
|
|
|
@@ -179,26 +181,21 @@ class SchemaResolver:
|
|
|
179
181
|
|
|
180
182
|
def __init__(self, working_directory=Path()):
|
|
181
183
|
self.working_directory = working_directory.resolve()
|
|
182
|
-
self._schema_cache: dict[str | Path,
|
|
184
|
+
self._schema_cache: dict[str | Path, Any] = {}
|
|
183
185
|
|
|
184
186
|
@staticmethod
|
|
185
187
|
def _get_branch(schema: dict, ref: str):
|
|
186
|
-
|
|
187
|
-
pointer = schema
|
|
188
|
-
for item in path:
|
|
189
|
-
if item:
|
|
190
|
-
pointer = pointer[item]
|
|
191
|
-
return pointer
|
|
188
|
+
return jsonpointer.resolve_pointer(schema, re.sub('^#', '', ref))
|
|
192
189
|
|
|
193
190
|
def load_contents(self, s: str | Path) -> tuple[dict, bool]:
|
|
194
191
|
"""
|
|
195
192
|
Load the contents of a schema. Can be overriden by subclasses to alter the loading process.
|
|
196
193
|
"""
|
|
197
|
-
contents
|
|
194
|
+
contents = self._schema_cache.get(s)
|
|
198
195
|
if contents is None:
|
|
199
|
-
contents
|
|
200
|
-
self._schema_cache[s] = contents
|
|
201
|
-
return contents
|
|
196
|
+
contents = read_contents(s)[0]
|
|
197
|
+
self._schema_cache[s] = contents
|
|
198
|
+
return load_json_yaml(contents)
|
|
202
199
|
|
|
203
200
|
def resolve_ref(self, ref: str | Path, from_schema: ReferencedSchema | None = None) -> tuple[Path | str, str]:
|
|
204
201
|
location = ref
|
|
@@ -229,7 +226,8 @@ class SchemaResolver:
|
|
|
229
226
|
|
|
230
227
|
return location, fragment
|
|
231
228
|
|
|
232
|
-
def resolve_schema(self, ref: str | Path, from_schema: ReferencedSchema | None = None
|
|
229
|
+
def resolve_schema(self, ref: str | Path, from_schema: ReferencedSchema | None = None,
|
|
230
|
+
force_contents: dict | None = None) -> ReferencedSchema | None:
|
|
233
231
|
chain = from_schema.chain + [from_schema] if from_schema else []
|
|
234
232
|
try:
|
|
235
233
|
schema_source, fragment = self.resolve_ref(ref, from_schema)
|
|
@@ -250,6 +248,8 @@ class SchemaResolver:
|
|
|
250
248
|
is_json=from_schema.is_json)
|
|
251
249
|
|
|
252
250
|
contents, is_json = self.load_contents(schema_source)
|
|
251
|
+
if force_contents:
|
|
252
|
+
contents = force_contents
|
|
253
253
|
if fragment:
|
|
254
254
|
return ReferencedSchema(location=schema_source, fragment=fragment,
|
|
255
255
|
subschema=SchemaResolver._get_branch(contents, fragment),
|
|
@@ -347,6 +347,8 @@ def resolve_context(ctx: Path | str | dict | list, expand_uris=True) -> Resolved
|
|
|
347
347
|
prefix, localpart = curie.split(':', 1)
|
|
348
348
|
else:
|
|
349
349
|
prefix, localpart = None, None
|
|
350
|
+
|
|
351
|
+
vocab = UNDEFINED
|
|
350
352
|
for c in reversed(ctx_stack):
|
|
351
353
|
if localpart:
|
|
352
354
|
# prefix:localpart format
|
|
@@ -355,9 +357,11 @@ def resolve_context(ctx: Path | str | dict | list, expand_uris=True) -> Resolved
|
|
|
355
357
|
prefix_uri = term_val if isinstance(term_val, str) else term_val.get('@id')
|
|
356
358
|
prefixes[prefix] = prefix_uri
|
|
357
359
|
return f"{prefix_uri}{localpart}"
|
|
358
|
-
elif '@vocab' in c:
|
|
359
|
-
# look for @vocab
|
|
360
|
-
|
|
360
|
+
elif '@vocab' in c and vocab is UNDEFINED:
|
|
361
|
+
# look for @vocab unless it has been overridden (e.g. set to null) somewhere down the chain
|
|
362
|
+
vocab = c['@vocab']
|
|
363
|
+
if isinstance(vocab, str):
|
|
364
|
+
return f"{c['@vocab']}{curie}"
|
|
361
365
|
|
|
362
366
|
return curie
|
|
363
367
|
|
|
@@ -389,7 +393,11 @@ def resolve_context(ctx: Path | str | dict | list, expand_uris=True) -> Resolved
|
|
|
389
393
|
resolved_ctx = {}
|
|
390
394
|
inner_prefixes = {}
|
|
391
395
|
for ctx_entry in inner_ctx:
|
|
392
|
-
|
|
396
|
+
if isinstance(ctx_entry, dict):
|
|
397
|
+
# Array entries must be wrapped with @context
|
|
398
|
+
resolved_entry = resolve_context({'@context': ctx_entry})
|
|
399
|
+
else:
|
|
400
|
+
resolved_entry = resolve_context(ctx_entry)
|
|
393
401
|
inner_prefixes.update(resolved_entry.prefixes)
|
|
394
402
|
resolved = ResolvedContext(merge_dicts(resolved_entry.context, resolved_ctx), inner_prefixes)
|
|
395
403
|
else:
|
|
@@ -448,12 +456,8 @@ class SchemaAnnotator:
|
|
|
448
456
|
def process_schema(self, location: Path | str | None,
|
|
449
457
|
default_context: str | Path | dict | None = None,
|
|
450
458
|
contents: dict | None = None) -> AnnotatedSchema | None:
|
|
451
|
-
resolved_schema = self.schema_resolver.resolve_schema(location)
|
|
452
|
-
|
|
453
|
-
# overriden
|
|
454
|
-
schema = contents
|
|
455
|
-
else:
|
|
456
|
-
schema = resolved_schema.subschema
|
|
459
|
+
resolved_schema = self.schema_resolver.resolve_schema(location, force_contents=contents)
|
|
460
|
+
schema = resolved_schema.subschema
|
|
457
461
|
|
|
458
462
|
if all(x not in schema for x in ('schema', 'openapi')):
|
|
459
463
|
validate_schema(schema)
|
|
@@ -482,8 +486,10 @@ class SchemaAnnotator:
|
|
|
482
486
|
updated_refs: set[int] = set()
|
|
483
487
|
|
|
484
488
|
def find_prop_context(prop, context_stack) -> dict | None:
|
|
489
|
+
vocab = UNDEFINED
|
|
485
490
|
for ctx in reversed(context_stack):
|
|
486
|
-
vocab
|
|
491
|
+
if vocab is UNDEFINED and '@vocab' in ctx:
|
|
492
|
+
vocab = ctx.get('@vocab')
|
|
487
493
|
if prop in ctx:
|
|
488
494
|
prop_ctx = ctx[prop]
|
|
489
495
|
if isinstance(prop_ctx, str):
|
|
@@ -501,7 +507,7 @@ class SchemaAnnotator:
|
|
|
501
507
|
elif ':' not in prop_id and prop_id not in JSON_LD_KEYWORDS:
|
|
502
508
|
result['@id'] = f"{vocab}{prop_id}"
|
|
503
509
|
return result
|
|
504
|
-
elif
|
|
510
|
+
elif isinstance(vocab, str):
|
|
505
511
|
return {'@id': f"{ctx['@vocab']}{prop}"}
|
|
506
512
|
|
|
507
513
|
def process_properties(obj: dict, context_stack: list[dict[str, Any]],
|
|
@@ -557,6 +563,13 @@ class SchemaAnnotator:
|
|
|
557
563
|
|
|
558
564
|
used_terms = set()
|
|
559
565
|
|
|
566
|
+
# Annotate definitions and $defs - can later be overridden if referenced from a different path
|
|
567
|
+
for p in ('definitions', '$defs'):
|
|
568
|
+
defs = subschema.get(p)
|
|
569
|
+
if defs and isinstance(defs, dict):
|
|
570
|
+
for entry in defs.values():
|
|
571
|
+
used_terms.update(process_subschema(entry, context_stack, from_schema, level + 1))
|
|
572
|
+
|
|
560
573
|
if '$ref' in subschema and id(subschema) not in updated_refs:
|
|
561
574
|
if self._ref_mapper:
|
|
562
575
|
subschema['$ref'] = self._ref_mapper(subschema['$ref'], subschema)
|
|
@@ -574,13 +587,6 @@ class SchemaAnnotator:
|
|
|
574
587
|
for entry in collection:
|
|
575
588
|
used_terms.update(process_subschema(entry, context_stack, from_schema, level + 1))
|
|
576
589
|
|
|
577
|
-
# Annotate definitions and $defs
|
|
578
|
-
for p in ('definitions', '$defs'):
|
|
579
|
-
defs = subschema.get(p)
|
|
580
|
-
if defs and isinstance(defs, dict):
|
|
581
|
-
for entry in defs.values():
|
|
582
|
-
used_terms.update(process_subschema(entry, context_stack, from_schema, level + 1))
|
|
583
|
-
|
|
584
590
|
for p in ('then', 'else', 'additionalProperties'):
|
|
585
591
|
branch = subschema.get(p)
|
|
586
592
|
if branch and isinstance(branch, dict):
|
|
@@ -862,8 +868,9 @@ class ContextBuilder:
|
|
|
862
868
|
if isinstance(term_value, str):
|
|
863
869
|
branch[term] = compact_uri(term_value)
|
|
864
870
|
elif isinstance(term_value, dict):
|
|
865
|
-
|
|
866
|
-
|
|
871
|
+
for k in CURIE_TERMS:
|
|
872
|
+
if k in term_value:
|
|
873
|
+
term_value[k] = compact_uri(term_value[k])
|
|
867
874
|
if len(term_value) == 1 and '@id' in term_value:
|
|
868
875
|
branch[term] = term_value['@id']
|
|
869
876
|
elif '@context' in term_value:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ogc_na
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.46
|
|
4
4
|
Summary: OGC Naming Authority tools
|
|
5
5
|
Author-email: Rob Atkinson <ratkinson@ogc.org>, Piotr Zaborowski <pzaborowski@ogc.org>, Alejandro Villar <avillar@ogc.org>
|
|
6
6
|
Project-URL: Homepage, https://github.com/opengeospatial/ogc-na-tools/
|
|
@@ -26,6 +26,7 @@ Requires-Dist: GitPython >=3.1.32
|
|
|
26
26
|
Requires-Dist: rfc3987
|
|
27
27
|
Requires-Dist: requests-cache
|
|
28
28
|
Requires-Dist: xmltodict
|
|
29
|
+
Requires-Dist: jsonpointer ~=2.4
|
|
29
30
|
Requires-Dist: setuptools
|
|
30
31
|
Provides-Extra: dev
|
|
31
32
|
Requires-Dist: mkdocs >=1.4.2 ; extra == 'dev'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
ogc/na/__init__.py,sha256=uzcNiJ3uKFNJ1HBfKxIwgAy2HMUFsLAe5RkrUg8ncac,464
|
|
2
|
-
ogc/na/_version.py,sha256=
|
|
3
|
-
ogc/na/annotate_schema.py,sha256=
|
|
2
|
+
ogc/na/_version.py,sha256=nKT1cOpmRV-LeICJaPCDMdhIUkMGhRcN3p0Hyw8DrwA,413
|
|
3
|
+
ogc/na/annotate_schema.py,sha256=bVzQ-YjQ0ULJxaLxWk5ZFaVTKky2TbEY91VlYMqxmSs,40335
|
|
4
4
|
ogc/na/domain_config.py,sha256=C6ao37dbXEKv_K7WcfzQgI3H1Hr3c4-3p24hgl2oH54,13896
|
|
5
5
|
ogc/na/download.py,sha256=2afrLyl4WsAlxkCgXsl47fs9mNKfDmhVpeT2iwNSoq0,3354
|
|
6
6
|
ogc/na/gsp.py,sha256=KGa2G9i8kPefYTHNPUDoXnNyF7Tiwt8K__Ew_Qa7eeg,6048
|
|
@@ -14,7 +14,7 @@ ogc/na/validation.py,sha256=5xjHH55NZKM8HtUk8XgVzm8W5ZlZY00u_qsWfXK_8dM,3732
|
|
|
14
14
|
ogc/na/input_filters/__init__.py,sha256=AhE7n_yECwxFKwOM3Jc0ft96TtF5i_Z-fHrS4HYOjaE,1179
|
|
15
15
|
ogc/na/input_filters/csv.py,sha256=nFfB1XQF_QApcGGzMqEvzD_b3pBtCtsfUECsZ9UGE6s,2616
|
|
16
16
|
ogc/na/input_filters/xml.py,sha256=9qYjp_w5JLInFM48zB15IYH9eTafjp1Aqd_8kfuW3aA,2074
|
|
17
|
-
ogc_na-0.3.
|
|
18
|
-
ogc_na-0.3.
|
|
19
|
-
ogc_na-0.3.
|
|
20
|
-
ogc_na-0.3.
|
|
17
|
+
ogc_na-0.3.46.dist-info/METADATA,sha256=gMk9QGd1n214nQuZUPe3vp7RdERy5yCus7q1lWTdJFk,3829
|
|
18
|
+
ogc_na-0.3.46.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
19
|
+
ogc_na-0.3.46.dist-info/top_level.txt,sha256=Kvy3KhzcIhNPT4_nZuJCmS946ptRr_MDyU4IIhZJhCY,4
|
|
20
|
+
ogc_na-0.3.46.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|