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 +2 -2
- ogc/na/annotate_schema.py +38 -11
- ogc/na/input_filters/xlsx.py +87 -0
- {ogc_na-0.3.55.dist-info → ogc_na-0.3.57.dist-info}/METADATA +19 -18
- {ogc_na-0.3.55.dist-info → ogc_na-0.3.57.dist-info}/RECORD +7 -6
- {ogc_na-0.3.55.dist-info → ogc_na-0.3.57.dist-info}/WHEEL +1 -1
- {ogc_na-0.3.55.dist-info → ogc_na-0.3.57.dist-info}/top_level.txt +0 -0
ogc/na/_version.py
CHANGED
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: ogc_na
|
|
3
|
-
Version: 0.3.
|
|
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
|
|
17
|
-
Requires-Dist: rdflib
|
|
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
|
|
23
|
+
Requires-Dist: requests>=2.30
|
|
24
24
|
Requires-Dist: jsonschema
|
|
25
|
-
Requires-Dist: GitPython
|
|
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
|
|
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
|
|
33
|
-
Requires-Dist: mkdocs-autorefs
|
|
34
|
-
Requires-Dist: mkdocs-gen-files
|
|
35
|
-
Requires-Dist: mkdocs-literate-nav
|
|
36
|
-
Requires-Dist: mkdocs-material
|
|
37
|
-
Requires-Dist: mkdocs-material-extensions
|
|
38
|
-
Requires-Dist: mkdocs-pymdownx-material-extras
|
|
39
|
-
Requires-Dist: mkdocs-section-index
|
|
40
|
-
Requires-Dist: mkdocstrings
|
|
41
|
-
Requires-Dist: mkdocstrings-python
|
|
42
|
-
Requires-Dist: mkdocs-markdownextradata-plugin
|
|
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=
|
|
3
|
-
ogc/na/annotate_schema.py,sha256=
|
|
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.
|
|
19
|
-
ogc_na-0.3.
|
|
20
|
-
ogc_na-0.3.
|
|
21
|
-
ogc_na-0.3.
|
|
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,,
|
|
File without changes
|