ogc-na 0.3.44__tar.gz → 0.3.46__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.

Potentially problematic release.


This version of ogc-na might be problematic. Click here for more details.

Files changed (54) hide show
  1. {ogc_na-0.3.44 → ogc_na-0.3.46}/PKG-INFO +2 -1
  2. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/_version.py +2 -2
  3. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/annotate_schema.py +41 -34
  4. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc_na.egg-info/PKG-INFO +2 -1
  5. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc_na.egg-info/requires.txt +1 -0
  6. {ogc_na-0.3.44 → ogc_na-0.3.46}/requirements.txt +1 -0
  7. {ogc_na-0.3.44 → ogc_na-0.3.46}/.github/workflows/mkdocs.yml +0 -0
  8. {ogc_na-0.3.44 → ogc_na-0.3.46}/.github/workflows/python-publish.yml +0 -0
  9. {ogc_na-0.3.44 → ogc_na-0.3.46}/.gitignore +0 -0
  10. {ogc_na-0.3.44 → ogc_na-0.3.46}/MANIFEST.in +0 -0
  11. {ogc_na-0.3.44 → ogc_na-0.3.46}/README.md +0 -0
  12. {ogc_na-0.3.44 → ogc_na-0.3.46}/docs/examples.md +0 -0
  13. {ogc_na-0.3.44 → ogc_na-0.3.46}/docs/gen_ref_pages.py +0 -0
  14. {ogc_na-0.3.44 → ogc_na-0.3.46}/docs/index.md +0 -0
  15. {ogc_na-0.3.44 → ogc_na-0.3.46}/docs/jsonld-uplift.md +0 -0
  16. {ogc_na-0.3.44 → ogc_na-0.3.46}/docs/tutorials.md +0 -0
  17. {ogc_na-0.3.44 → ogc_na-0.3.46}/mkdocs.yml +0 -0
  18. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/__init__.py +0 -0
  19. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/domain_config.py +0 -0
  20. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/download.py +0 -0
  21. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/gsp.py +0 -0
  22. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/ingest_json.py +0 -0
  23. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/input_filters/__init__.py +0 -0
  24. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/input_filters/csv.py +0 -0
  25. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/input_filters/xml.py +0 -0
  26. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/models.py +0 -0
  27. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/profile.py +0 -0
  28. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/provenance.py +0 -0
  29. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/update_vocabs.py +0 -0
  30. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/util.py +0 -0
  31. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc/na/validation.py +0 -0
  32. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc_na.egg-info/SOURCES.txt +0 -0
  33. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc_na.egg-info/dependency_links.txt +0 -0
  34. {ogc_na-0.3.44 → ogc_na-0.3.46}/ogc_na.egg-info/top_level.txt +0 -0
  35. {ogc_na-0.3.44 → ogc_na-0.3.46}/pyproject.toml +0 -0
  36. {ogc_na-0.3.44 → ogc_na-0.3.46}/rdf/catalog-v001.xml +0 -0
  37. {ogc_na-0.3.44 → ogc_na-0.3.46}/rdf/domaincfg.vocab.ttl +0 -0
  38. {ogc_na-0.3.44 → ogc_na-0.3.46}/setup.cfg +0 -0
  39. {ogc_na-0.3.44 → ogc_na-0.3.46}/setup.py +0 -0
  40. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/__init__.py +0 -0
  41. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/empty.ttl +0 -0
  42. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/headers.csv +0 -0
  43. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/no-headers.csv +0 -0
  44. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/profile_tree.ttl +0 -0
  45. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/profile_tree_cyclic.ttl +0 -0
  46. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/sample-context.jsonld +0 -0
  47. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/sample-schema-prop-c.yml +0 -0
  48. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/sample-schema.yml +0 -0
  49. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/schema-vocab.yml +0 -0
  50. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/data/uplift_context_valid.yml +0 -0
  51. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/test_annotate_schema.py +0 -0
  52. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/test_ingest_json.py +0 -0
  53. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/test_input_filters_csv.py +0 -0
  54. {ogc_na-0.3.44 → ogc_na-0.3.46}/test/test_profile.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ogc_na
3
- Version: 0.3.44
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"
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.3.44'
16
- __version_tuple__ = version_tuple = (0, 3, 44)
15
+ __version__ = version = '0.3.46'
16
+ __version_tuple__ = version_tuple = (0, 3, 46)
@@ -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, tuple[Any, bool]] = {}
184
+ self._schema_cache: dict[str | Path, Any] = {}
183
185
 
184
186
  @staticmethod
185
187
  def _get_branch(schema: dict, ref: str):
186
- path = re.sub(r'^#?/?', '', ref).split('/')
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, is_json = self._schema_cache.get(s, (None, False))
194
+ contents = self._schema_cache.get(s)
198
195
  if contents is None:
199
- contents, is_json = load_json_yaml(read_contents(s)[0])
200
- self._schema_cache[s] = contents, is_json
201
- return contents, is_json
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) -> ReferencedSchema | 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
- return f"{c['@vocab']}{curie}"
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
- resolved_entry = resolve_context(ctx_entry)
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
- if contents:
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 = ctx.get('@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 '@vocab' in ctx:
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
- if '@id' in term_value:
866
- term_value['@id'] = compact_uri(term_value['@id'])
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.44
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"
@@ -11,6 +11,7 @@ GitPython>=3.1.32
11
11
  rfc3987
12
12
  requests-cache
13
13
  xmltodict
14
+ jsonpointer~=2.4
14
15
  setuptools
15
16
 
16
17
  [dev]
@@ -11,6 +11,7 @@ GitPython>=3.1.32
11
11
  rfc3987
12
12
  requests-cache
13
13
  xmltodict
14
+ jsonpointer~=2.4
14
15
 
15
16
  # to be removed once https://github.com/RDFLib/pySHACL/issues/212 is fixed
16
17
  setuptools
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes