ogc-na 0.2.9__py3-none-any.whl → 0.2.11__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/annotate_schema.py CHANGED
@@ -323,7 +323,8 @@ class SchemaAnnotator:
323
323
 
324
324
  def __init__(self, fn: Path | str | None = None, url: str | None = None,
325
325
  follow_refs: bool = True, ref_root: Path | str | None = None,
326
- context: str | Path | dict | None = None):
326
+ context: str | Path | dict | None = None,
327
+ ref_mapper: Callable[[str], str] | None = None):
327
328
  """
328
329
  :param fn: file path to load (root schema)
329
330
  :param url: URL to load (root schema)
@@ -334,9 +335,29 @@ class SchemaAnnotator:
334
335
  self.ref_root = Path(ref_root) if ref_root else None
335
336
  self._follow_refs = follow_refs
336
337
  self._provided_context = context
338
+ self._ref_mapper = ref_mapper
337
339
 
338
340
  self._process_schema(fn, url)
339
341
 
342
+ def _follow_ref(self, subschema, schema_fn: Path, schema_url: str, base_url: str | None):
343
+ if not isinstance(subschema, dict) or '$ref' not in subschema:
344
+ return
345
+
346
+ if self._ref_mapper:
347
+ subschema['$ref'] = self._ref_mapper(subschema['$ref'])
348
+
349
+ if not self._follow_refs:
350
+ return
351
+
352
+ ref_fn, ref_url = resolve_ref(subschema['$ref'], schema_fn, schema_url, base_url)
353
+ ref = ref_fn or ref_url
354
+
355
+ if ref in self.schemas:
356
+ logger.info(' >> Found $ref to already-processed schema: %s', ref)
357
+ else:
358
+ logger.info(' >> Found $ref to new schema: %s', ref)
359
+ self._process_schema(url=ref_url, fn=ref_fn)
360
+
340
361
  def _process_schema(self, fn: Path | str | None = None, url: str | None = None):
341
362
  contents, base_url = read_contents(fn, url)
342
363
  schema, is_json = load_json_yaml(contents)
@@ -381,24 +402,26 @@ class SchemaAnnotator:
381
402
  prop_value[ANNOTATION_ID] = terms[prop]
382
403
  if prop in types:
383
404
  prop_value[ANNOTATION_TYPE] = types[prop]
384
- if '$ref' in prop_value and self._follow_refs:
385
-
386
- ref_fn, ref_url = resolve_ref(prop_value['$ref'], fn, url, base_url)
387
- ref = ref_fn or ref_url
388
405
 
389
- if ref in self.schemas:
390
- logger.info(' >> Found $ref to already-processed schema: %s', ref)
391
- else:
392
- logger.info(' >> Found $ref to new schema: %s', prop_value['$ref'])
393
- if ref_url:
394
- self._process_schema(url=ref)
395
- else:
396
- self._process_schema(fn=ref)
406
+ process_subschema(prop_value)
397
407
 
398
408
  properties.update({p: {ANNOTATION_ID: terms[p]} for p in empty_properties if p in terms})
399
409
 
400
410
  def process_subschema(subschema):
401
411
 
412
+ if not subschema:
413
+ return
414
+
415
+ self._follow_ref(subschema, fn, url, base_url)
416
+
417
+ # Annotate oneOf, allOf, anyOf
418
+ for p in ('oneOf', 'allOf', 'anyOf'):
419
+ collection = subschema.get(p)
420
+ if collection and isinstance(collection, list):
421
+ for entry in collection:
422
+ process_subschema(entry)
423
+
424
+ # Annotate main schema
402
425
  schema_type = subschema.get('type')
403
426
  if not schema_type and 'properties' in subschema:
404
427
  schema_type = 'object'
@@ -407,8 +430,9 @@ class SchemaAnnotator:
407
430
  process_properties(subschema)
408
431
  elif schema_type == 'array':
409
432
  for k in ('prefixItems', 'items', 'contains'):
410
- process_properties(subschema.get(k))
433
+ process_subschema(subschema.get(k))
411
434
 
435
+ # Annotate $defs
412
436
  for defs_prop in ('$defs', 'definitions'):
413
437
  defs_value = subschema.get(defs_prop)
414
438
  if isinstance(defs_value, dict):
@@ -433,7 +457,7 @@ class ContextBuilder:
433
457
  """
434
458
 
435
459
  def __init__(self, fn: Path | str | None = None, url: str | None = None,
436
- compact: bool = True):
460
+ compact: bool = True, ref_mapper: Callable[[str], str] | None = None):
437
461
  """
438
462
  :param fn: file to load the annotated schema from
439
463
  :param url: URL to load the annotated schema from
@@ -441,6 +465,7 @@ class ContextBuilder:
441
465
  self.context = {'@context': {}}
442
466
  self._parsed_schemas: dict[str | Path, dict] = {}
443
467
  self.compact = compact
468
+ self._ref_mapper = ref_mapper
444
469
 
445
470
  context = self._build_context(fn, url)
446
471
  self.context = {'@context': context}
@@ -482,7 +507,7 @@ class ContextBuilder:
482
507
  if prefixes:
483
508
  own_context.update(prefixes)
484
509
 
485
- def read_properties(where: dict):
510
+ def read_properties(where: dict, into_context: dict):
486
511
  if not isinstance(where, dict):
487
512
  return
488
513
  for prop, prop_val in where.get('properties', {}).items():
@@ -493,57 +518,56 @@ class ContextBuilder:
493
518
  if ANNOTATION_TYPE in prop_val:
494
519
  prop_context['@type'] = compact_uri(prop_val[ANNOTATION_TYPE])
495
520
 
496
- if '$ref' in prop_val:
497
- ref_fn, ref_url = resolve_ref(prop_val['$ref'], fn, url, base_url)
498
- prop_context['@context'] = self._build_context(ref_fn, ref_url)
521
+ process_subschema(prop_val, prop_context.setdefault('@context', {}))
522
+
523
+ if not prop_context['@context']:
524
+ prop_context.pop('@context', None)
499
525
 
500
- if len(prop_context) == 1:
526
+ if isinstance(prop_context, dict) and len(prop_context) == 1:
501
527
  # shorten to just the id
502
528
  prop_context = next(iter(prop_context.values()))
503
529
 
504
- own_context[prop] = prop_context
530
+ into_context[prop] = prop_context
531
+
532
+ def process_subschema(ss, into_context: dict):
505
533
 
506
- def process_subschema(ss):
507
534
  if isinstance(ss, dict):
508
535
  if '$ref' in ss:
509
536
  ref_fn, ref_url = resolve_ref(ss['$ref'], fn, url, base_url)
510
537
  merge_dicts(self._build_context(ref_fn, ref_url), own_context)
511
- else:
512
- read_properties(ss)
538
+ read_properties(ss, into_context)
513
539
 
514
- for i in ('allOf', 'anyOf', 'oneOf'):
515
- l = schema.get(i)
516
- if isinstance(l, list):
517
- for sub_schema in l:
518
- process_subschema(sub_schema)
540
+ for i in ('allOf', 'anyOf', 'oneOf'):
541
+ l = ss.get(i)
542
+ if isinstance(l, list):
543
+ for sub_schema in l:
544
+ process_subschema(sub_schema, into_context)
519
545
 
520
- for i in ('$defs', 'definitions'):
521
- d = schema.get(i)
522
- if isinstance(d, dict):
523
- for sub_schema in d.values():
524
- process_subschema(sub_schema)
546
+ for i in ('$defs', 'definitions'):
547
+ d = ss.get(i)
548
+ if isinstance(d, dict):
549
+ for sub_schema in d.values():
550
+ process_subschema(sub_schema, into_context)
525
551
 
526
- read_properties(schema)
552
+ process_subschema(schema, own_context)
527
553
 
528
554
  if self.compact:
529
- context_props = set(own_context.keys())
530
- compact_context = {}
531
- for prop, prop_val in own_context.items():
532
- compact_context[prop] = prop_val
533
- if not isinstance(prop_val, dict):
534
- continue
535
- prop_context = prop_val.pop('@context', None)
536
- if not isinstance(prop_context, dict):
537
- continue
538
- for term, term_val in prop_context.items():
539
- if not term.startswith('@') and term in context_props:
540
- compact_context.setdefault(prop, {}).setdefault('@context', {})[term] = term_val
541
- else:
542
- compact_context[term] = term_val
543
- if len(compact_context[prop]) == 1 and '@id' in compact_context[prop]:
544
- compact_context[prop] = compact_context[prop]['@id']
545
-
546
- own_context = compact_context
555
+
556
+ def compact_branch(branch, existing_terms):
557
+
558
+ for term in list(branch.keys()):
559
+ if term[0] == '@':
560
+ # skip special terms
561
+ continue
562
+ if term in existing_terms and existing_terms[term] == branch[term]:
563
+ # same term exists in ancestor -> delete
564
+ del branch[term]
565
+
566
+ for term, term_value in branch.items():
567
+ if isinstance(term_value, dict) and '@context' in term_value:
568
+ compact_branch(term_value['@context'], {**existing_terms, **branch})
569
+
570
+ compact_branch(own_context, {})
547
571
 
548
572
  self._parsed_schemas[fn or url] = own_context
549
573
  return own_context
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ogc-na
3
- Version: 0.2.9
3
+ Version: 0.2.11
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/
@@ -1,5 +1,5 @@
1
1
  ogc/na/__init__.py,sha256=uzcNiJ3uKFNJ1HBfKxIwgAy2HMUFsLAe5RkrUg8ncac,464
2
- ogc/na/annotate_schema.py,sha256=L8RbhjIDNdKUfwqd2XYe-DOzywWOY-FFjPIeJzazghA,21772
2
+ ogc/na/annotate_schema.py,sha256=wEvqVbdRXpAKSLQz231H7B11m-mZekDrtULjXPMMIVk,22473
3
3
  ogc/na/domain_config.py,sha256=x_X4YiNo1etaa4N6KrZFRsFgWPPKk1rLqVE3ZP3rrps,13030
4
4
  ogc/na/download.py,sha256=2afrLyl4WsAlxkCgXsl47fs9mNKfDmhVpeT2iwNSoq0,3354
5
5
  ogc/na/ingest_json.py,sha256=3g47V01eKAPGK6EVGxyzhJhp4uE3mSfvI5gV4L3awZQ,32327
@@ -10,7 +10,7 @@ ogc/na/util.py,sha256=ySu2mSAhUYwYFH78Bmo9Z35DM4fHqb1ExLEYPjno3fs,7990
10
10
  ogc/na/validation.py,sha256=FkXx1Pwot4ztg9Vv2LrODfYxpknG9-67BmY3Ep7avd4,3535
11
11
  ogc/na/input_filters/__init__.py,sha256=PvWEI-rj5NNR_Cl903wHtS08oTywjDYEfappY5JtVkI,1169
12
12
  ogc/na/input_filters/csv.py,sha256=O2E3ivjP9i5tGtyvb6UjmR4eM7toVkzP58EUm6bxvfw,2530
13
- ogc_na-0.2.9.dist-info/METADATA,sha256=NwoRgJZTf5utbdHlVVcNsJhEwqzE2A1FAFtx61fXaJk,3527
14
- ogc_na-0.2.9.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
15
- ogc_na-0.2.9.dist-info/top_level.txt,sha256=Kvy3KhzcIhNPT4_nZuJCmS946ptRr_MDyU4IIhZJhCY,4
16
- ogc_na-0.2.9.dist-info/RECORD,,
13
+ ogc_na-0.2.11.dist-info/METADATA,sha256=2VI9Kdkv6M2EkPv3AtvUe2uUwz5mu10zWa7SVaMW8b0,3528
14
+ ogc_na-0.2.11.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
15
+ ogc_na-0.2.11.dist-info/top_level.txt,sha256=Kvy3KhzcIhNPT4_nZuJCmS946ptRr_MDyU4IIhZJhCY,4
16
+ ogc_na-0.2.11.dist-info/RECORD,,