ogc-na 0.3.55__py3-none-any.whl → 0.3.57__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 CHANGED
@@ -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.55'
16
- __version_tuple__ = version_tuple = (0, 3, 55)
15
+ __version__ = version = '0.3.57'
16
+ __version_tuple__ = version_tuple = (0, 3, 57)
ogc/na/annotate_schema.py CHANGED
@@ -123,6 +123,7 @@ import json
123
123
  import logging
124
124
  import re
125
125
  import sys
126
+ from collections import deque
126
127
  from operator import attrgetter
127
128
  from pathlib import Path
128
129
  from typing import Any, AnyStr, Callable, Sequence, Iterable
@@ -177,6 +178,7 @@ class ReferencedSchema:
177
178
  chain: list = dataclasses.field(default_factory=list)
178
179
  ref: str | Path = None
179
180
  is_json: bool = False
181
+ anchors: dict[str, Any] = dataclasses.field(default_factory=dict)
180
182
 
181
183
 
182
184
  @dataclasses.dataclass
@@ -192,8 +194,27 @@ class SchemaResolver:
192
194
  self._schema_cache: dict[str | Path, Any] = {}
193
195
 
194
196
  @staticmethod
195
- def _get_branch(schema: dict, ref: str):
196
- return jsonpointer.resolve_pointer(schema, re.sub('^#', '', ref))
197
+ def _get_branch(schema: dict, ref: str, anchors: dict[str, Any] = None):
198
+ ref = re.sub('^#', '', ref)
199
+ if anchors and ref in anchors:
200
+ return anchors[ref]
201
+ return jsonpointer.resolve_pointer(schema, ref)
202
+
203
+ @staticmethod
204
+ def _find_anchors(schema: dict) -> dict[str, Any]:
205
+ anchors = {}
206
+
207
+ pending = deque((schema,))
208
+ while pending:
209
+ current = pending.popleft()
210
+ if isinstance(current, dict):
211
+ if '$anchor' in current:
212
+ anchors[current['$anchor']] = current
213
+ pending.extend(current.values())
214
+ elif isinstance(current, list):
215
+ pending.extend(current)
216
+
217
+ return anchors
197
218
 
198
219
  def load_contents(self, s: str | Path) -> tuple[dict, bool]:
199
220
  """
@@ -252,11 +273,13 @@ class SchemaResolver:
252
273
  raise ValueError('Local ref provided without an anchor: ' + ref)
253
274
  return ReferencedSchema(location=from_schema.location,
254
275
  fragment=ref[1:],
255
- subschema=SchemaResolver._get_branch(from_schema.full_contents, ref),
276
+ subschema=SchemaResolver._get_branch(from_schema.full_contents, ref,
277
+ from_schema.anchors),
256
278
  full_contents=from_schema.full_contents,
257
279
  chain=chain,
258
280
  ref=ref,
259
- is_json=from_schema.is_json)
281
+ is_json=from_schema.is_json,
282
+ anchors=from_schema.anchors)
260
283
 
261
284
  if force_contents:
262
285
  is_json = False
@@ -269,20 +292,23 @@ class SchemaResolver:
269
292
  contents = force_contents
270
293
  else:
271
294
  contents, is_json = self.load_contents(schema_source)
295
+ anchors = SchemaResolver._find_anchors(contents)
272
296
  if fragment:
273
297
  return ReferencedSchema(location=schema_source, fragment=fragment,
274
- subschema=SchemaResolver._get_branch(contents, fragment),
298
+ subschema=SchemaResolver._get_branch(contents, fragment, anchors),
275
299
  full_contents=contents,
276
300
  chain=chain,
277
301
  ref=ref,
278
- is_json=is_json)
302
+ is_json=is_json,
303
+ anchors=anchors)
279
304
  else:
280
305
  return ReferencedSchema(location=schema_source,
281
306
  subschema=contents,
282
307
  full_contents=contents,
283
308
  chain=chain,
284
309
  ref=ref,
285
- is_json=is_json)
310
+ is_json=is_json,
311
+ anchors=anchors)
286
312
  except Exception as e:
287
313
  f = f" from {from_schema.location}" if from_schema else ''
288
314
  raise IOError(f"Error resolving reference {ref}{f}") from e
@@ -522,7 +548,7 @@ class SchemaAnnotator:
522
548
  if vocab and ':' not in prop_ctx and prop_ctx not in JSON_LD_KEYWORDS:
523
549
  prop_ctx = f"{vocab}{prop_ctx}"
524
550
  return {'@id': prop_ctx}
525
- elif '@id' not in prop_ctx and not vocab:
551
+ elif '@id' not in prop_ctx and '@reverse' not in prop_ctx and not vocab:
526
552
  raise ValueError(f'Missing @id for property {prop} in context {json.dumps(ctx, indent=2)}')
527
553
  else:
528
554
  result = {k: v for k, v in prop_ctx.items() if k in JSON_LD_KEYWORDS}
@@ -751,10 +777,11 @@ class ContextBuilder:
751
777
  self._missed_properties[full_property_path_str] = False
752
778
  prop_context['@' + term[len(ANNOTATION_PREFIX):]] = term_val
753
779
 
754
- if isinstance(prop_context.get('@id'), str):
755
- self.visited_properties[full_property_path_str] = prop_context['@id']
780
+ if isinstance(prop_context.get('@id'), str) or isinstance(prop_context.get('@reverse'), str):
781
+ prop_id_value = prop_context.get('@id', prop_context.get('@reverse'))
782
+ self.visited_properties[full_property_path_str] = prop_id_value
756
783
  self._missed_properties[full_property_path_str] = False
757
- if prop_context['@id'] in ('@nest', '@graph'):
784
+ if prop_id_value in ('@nest', '@graph'):
758
785
  merge_contexts(onto_context, process_subschema(prop_val, from_schema, full_property_path))
759
786
  else:
760
787
  merge_contexts(prop_context['@context'],
@@ -0,0 +1,87 @@
1
+ """
2
+ Excel (XLSX) Input filter for ingest_json.
3
+
4
+ Processes Excel XLSX files with [openpyxl](https://openpyxl.readthedocs.io/en/stable/).
5
+
6
+ Configuration values:
7
+
8
+ * `worksheet` (default: `None`): The name of the worksheet to process. If `None`, the default one will be used.
9
+ * `rows` (default: `dict`): type of elements in the result list:
10
+ * `dict`: elements will be dictionaries, with the keys taken from the `header-row`.
11
+ * `list`: each resulting row will be an array values.
12
+ * `header-row` (default: `0`): if `rows` is `dict`, the (0-based) index of the header row. All rows before the
13
+ header row will be skipped.
14
+ * `skip-rows` (default: `0`): number of rows to skip at the beginning of the file (apart from the header and pre-header
15
+ ones if `rows` is `dict`).
16
+ * `skip-empty-rows` (default: `True`): whether to omit empty rows (i.e., those with no values) from the result.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ from datetime import datetime
21
+ from io import BytesIO
22
+ from typing import Any
23
+ from openpyxl import load_workbook
24
+ from openpyxl.cell import Cell
25
+
26
+ from ogc.na import util
27
+
28
+ DEFAULT_CONF = {
29
+ 'worksheet': None,
30
+ 'rows': 'dict',
31
+ 'header-row': 0,
32
+ 'skip-rows': 0,
33
+ 'skip-empty-rows': True,
34
+ }
35
+
36
+
37
+ def _cell_to_json(c: Cell) -> str | float | int | None:
38
+ if isinstance(c.value, datetime):
39
+ return c.value.isoformat()
40
+ return c.value
41
+
42
+
43
+ def apply_filter(content: bytes, conf: dict[str, Any] | None) -> tuple[dict[str, Any] | list, dict[str, Any] | None]:
44
+ conf = util.deep_update(DEFAULT_CONF, conf) if conf else DEFAULT_CONF
45
+
46
+ metadata = {
47
+ 'filter': {
48
+ 'conf': conf,
49
+ },
50
+ }
51
+
52
+ wb = load_workbook(filename=BytesIO(content), read_only=True)
53
+ if conf['worksheet']:
54
+ ws = wb[conf['worksheet']]
55
+ else:
56
+ ws = wb.worksheets[0]
57
+ rows = ws.rows
58
+ metadata['worksheet'] = ws.title
59
+
60
+ headers = None
61
+ if conf['rows'] == 'dict':
62
+ header_row = max(conf['header-row'], 0)
63
+ # Skip to header row
64
+ for i in range(header_row):
65
+ next(rows, None)
66
+ headers = next(rows, [])
67
+ if not headers:
68
+ return [], None
69
+ else:
70
+ headers = [_cell_to_json(c) for c in headers]
71
+ metadata['headers'] = headers
72
+
73
+ for i in range(conf['skip-rows']):
74
+ next(rows, None)
75
+
76
+ result = []
77
+ for row in rows:
78
+ row_values = [_cell_to_json(c) for c in row]
79
+ if conf['skip-empty-rows'] and not any(c is not None for c in row_values):
80
+ # skip empty rows
81
+ continue
82
+ if conf['rows'] == 'list':
83
+ result.append(row_values)
84
+ else:
85
+ result.append(dict(zip(headers, row_values)))
86
+
87
+ return result, metadata
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: ogc_na
3
- Version: 0.3.55
3
+ Version: 0.3.57
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/
@@ -13,33 +13,34 @@ Classifier: Topic :: Utilities
13
13
  Classifier: Topic :: Software Development :: Libraries
14
14
  Requires-Python: >=3.7
15
15
  Description-Content-Type: text/markdown
16
- Requires-Dist: pyshacl >=0.19
17
- Requires-Dist: rdflib >=6.3.0
16
+ Requires-Dist: pyshacl>=0.19
17
+ Requires-Dist: rdflib>=6.3.0
18
18
  Requires-Dist: html5lib
19
19
  Requires-Dist: jq
20
20
  Requires-Dist: jsonpath-ng
21
21
  Requires-Dist: PyYAML
22
22
  Requires-Dist: wcmatch
23
- Requires-Dist: requests >=2.30
23
+ Requires-Dist: requests>=2.30
24
24
  Requires-Dist: jsonschema
25
- Requires-Dist: GitPython >=3.1.32
25
+ 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
+ Requires-Dist: jsonpointer~=2.4
30
+ Requires-Dist: openpyxl~=3.1.5
30
31
  Requires-Dist: setuptools
31
32
  Provides-Extra: dev
32
- Requires-Dist: mkdocs >=1.4.2 ; extra == 'dev'
33
- Requires-Dist: mkdocs-autorefs ; extra == 'dev'
34
- Requires-Dist: mkdocs-gen-files ; extra == 'dev'
35
- Requires-Dist: mkdocs-literate-nav ; extra == 'dev'
36
- Requires-Dist: mkdocs-material ; extra == 'dev'
37
- Requires-Dist: mkdocs-material-extensions ; extra == 'dev'
38
- Requires-Dist: mkdocs-pymdownx-material-extras ; extra == 'dev'
39
- Requires-Dist: mkdocs-section-index ; extra == 'dev'
40
- Requires-Dist: mkdocstrings ; extra == 'dev'
41
- Requires-Dist: mkdocstrings-python ; extra == 'dev'
42
- Requires-Dist: mkdocs-markdownextradata-plugin ; extra == 'dev'
33
+ Requires-Dist: mkdocs>=1.4.2; extra == "dev"
34
+ Requires-Dist: mkdocs-autorefs; extra == "dev"
35
+ Requires-Dist: mkdocs-gen-files; extra == "dev"
36
+ Requires-Dist: mkdocs-literate-nav; extra == "dev"
37
+ Requires-Dist: mkdocs-material; extra == "dev"
38
+ Requires-Dist: mkdocs-material-extensions; extra == "dev"
39
+ Requires-Dist: mkdocs-pymdownx-material-extras; extra == "dev"
40
+ Requires-Dist: mkdocs-section-index; extra == "dev"
41
+ Requires-Dist: mkdocstrings; extra == "dev"
42
+ Requires-Dist: mkdocstrings-python; extra == "dev"
43
+ Requires-Dist: mkdocs-markdownextradata-plugin; extra == "dev"
43
44
 
44
45
  # ogc-na-tools
45
46
 
@@ -1,6 +1,6 @@
1
1
  ogc/na/__init__.py,sha256=uzcNiJ3uKFNJ1HBfKxIwgAy2HMUFsLAe5RkrUg8ncac,464
2
- ogc/na/_version.py,sha256=vA6gPTjPSdC1gxj6eZa79wc5Se9JVwdnhpHXCsZkLbU,413
3
- ogc/na/annotate_schema.py,sha256=cjKZPKNOEUSghcQH9qCOiE2-Evr0VFyYMN2NkUMz5wo,42647
2
+ ogc/na/_version.py,sha256=KqIVwYBdIdahVzuj89W2dfY5Y-ewSsfE6L9PQnp8tPw,413
3
+ ogc/na/annotate_schema.py,sha256=YtxL9pOeeVk9CubvnByUMh7nZUJYZCDQ60hXEvtiR6g,43869
4
4
  ogc/na/domain_config.py,sha256=ORzITa1rTrD1MQdpWYrIVW5SwSa9lJd3hnyHIxNgiIU,13947
5
5
  ogc/na/download.py,sha256=2afrLyl4WsAlxkCgXsl47fs9mNKfDmhVpeT2iwNSoq0,3354
6
6
  ogc/na/exceptions.py,sha256=cwvnq79ih90T9lfwJww0zOx_QwuICaUvlo3Mc8m8ouA,85
@@ -14,8 +14,9 @@ ogc/na/util.py,sha256=Ztju3g1YuguUDbk4n2RJfCrl_IIzNAj7linfy24T6VA,12067
14
14
  ogc/na/validation.py,sha256=5xjHH55NZKM8HtUk8XgVzm8W5ZlZY00u_qsWfXK_8dM,3732
15
15
  ogc/na/input_filters/__init__.py,sha256=AhE7n_yECwxFKwOM3Jc0ft96TtF5i_Z-fHrS4HYOjaE,1179
16
16
  ogc/na/input_filters/csv.py,sha256=nFfB1XQF_QApcGGzMqEvzD_b3pBtCtsfUECsZ9UGE6s,2616
17
+ ogc/na/input_filters/xlsx.py,sha256=X9EpFgC9WwHQD8iUJRGdaDYfgiLKjXPdhTVhDmNPAQ0,2730
17
18
  ogc/na/input_filters/xml.py,sha256=9qYjp_w5JLInFM48zB15IYH9eTafjp1Aqd_8kfuW3aA,2074
18
- ogc_na-0.3.55.dist-info/METADATA,sha256=FPql5ZiyEyfGR0_tSciYAakCV0BkLfWdHJMmzPZaJME,3829
19
- ogc_na-0.3.55.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
20
- ogc_na-0.3.55.dist-info/top_level.txt,sha256=Kvy3KhzcIhNPT4_nZuJCmS946ptRr_MDyU4IIhZJhCY,4
21
- ogc_na-0.3.55.dist-info/RECORD,,
19
+ ogc_na-0.3.57.dist-info/METADATA,sha256=dcn9t_MBayKk9qKGfH5an7jKwcCpmK8QtDovmc5Ljmw,3843
20
+ ogc_na-0.3.57.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
21
+ ogc_na-0.3.57.dist-info/top_level.txt,sha256=Kvy3KhzcIhNPT4_nZuJCmS946ptRr_MDyU4IIhZJhCY,4
22
+ ogc_na-0.3.57.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5