spinta 0.2.dev18__py3-none-any.whl → 0.2.dev19__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.
- spinta/__init__.py +2 -0
- spinta/backends/postgresql/commands/summary.py +2 -2
- spinta/manifests/dict/components.py +102 -1
- spinta/manifests/dict/helpers.py +271 -297
- spinta/manifests/helpers.py +3 -3
- spinta/manifests/sql/helpers.py +8 -2
- spinta/nodes.py +4 -0
- spinta/testing/pytest.py +6 -2
- {spinta-0.2.dev18.dist-info → spinta-0.2.dev19.dist-info}/METADATA +1 -1
- {spinta-0.2.dev18.dist-info → spinta-0.2.dev19.dist-info}/RECORD +13 -13
- {spinta-0.2.dev18.dist-info → spinta-0.2.dev19.dist-info}/WHEEL +0 -0
- {spinta-0.2.dev18.dist-info → spinta-0.2.dev19.dist-info}/entry_points.txt +0 -0
- {spinta-0.2.dev18.dist-info → spinta-0.2.dev19.dist-info}/licenses/LICENSE +0 -0
spinta/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@ from spinta.backends.helpers import get_table_name
|
|
|
6
6
|
from spinta.backends.postgresql.helpers.name import get_pg_table_name, get_pg_column_name
|
|
7
7
|
from spinta.core.ufuncs import Expr
|
|
8
8
|
from spinta.types.datatype import Integer, Number, Boolean, String, Date, DateTime, Time, Ref
|
|
9
|
-
from spinta import commands
|
|
9
|
+
from spinta import commands, HTTP_URL_PREFIXES
|
|
10
10
|
from spinta.components import Context, Property
|
|
11
11
|
from spinta.components import Model
|
|
12
12
|
from spinta.exceptions import NotFoundError, NotImplementedFeature, InvalidRequestQuery
|
|
@@ -322,7 +322,7 @@ def summary(context: Context, dtype: Ref, backend: PostgreSQL, **kwargs):
|
|
|
322
322
|
prefixes = dtype.model.external.dataset.prefixes
|
|
323
323
|
label = None
|
|
324
324
|
if uri and ":" in uri:
|
|
325
|
-
if uri.startswith(
|
|
325
|
+
if uri.startswith(HTTP_URL_PREFIXES):
|
|
326
326
|
label = uri
|
|
327
327
|
else:
|
|
328
328
|
split = uri.split(":")
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import dataclasses
|
|
1
2
|
from enum import Enum
|
|
2
3
|
|
|
3
|
-
|
|
4
4
|
from spinta.manifests.components import Manifest
|
|
5
|
+
from spinta.manifests.helpers import TypeDetector
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class DictFormat(Enum):
|
|
@@ -30,3 +31,103 @@ class XmlManifest(DictManifest):
|
|
|
30
31
|
@staticmethod
|
|
31
32
|
def detect_from_path(path: str) -> bool:
|
|
32
33
|
return path.endswith(".xml")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclasses.dataclass
|
|
37
|
+
class _MappedProperties:
|
|
38
|
+
name: str
|
|
39
|
+
source: str
|
|
40
|
+
extra: str
|
|
41
|
+
type_detector: TypeDetector
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclasses.dataclass
|
|
45
|
+
class _MappedModels:
|
|
46
|
+
name: str
|
|
47
|
+
source: str
|
|
48
|
+
properties: dict[str, _MappedProperties]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclasses.dataclass
|
|
52
|
+
class _MappedDataset:
|
|
53
|
+
dataset: str
|
|
54
|
+
resource: str
|
|
55
|
+
models: dict[str, dict[str, _MappedModels]]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclasses.dataclass
|
|
59
|
+
class _MappingMeta:
|
|
60
|
+
is_blank_node: bool
|
|
61
|
+
blank_node_name: str
|
|
62
|
+
blank_node_source: str
|
|
63
|
+
seperator: str
|
|
64
|
+
recursive_descent: str
|
|
65
|
+
remove_array_suffix: bool
|
|
66
|
+
model_source_prefix: str
|
|
67
|
+
check_namespace: bool
|
|
68
|
+
namespace_prefixes: dict[str, list[str]]
|
|
69
|
+
namespace_seperator: str
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def get_for(cls, manifest_type: DictFormat) -> "_MappingMeta":
|
|
73
|
+
if manifest_type == DictFormat.JSON:
|
|
74
|
+
mapping_meta = _MappingMeta.for_json()
|
|
75
|
+
elif manifest_type in (DictFormat.XML, DictFormat.HTML):
|
|
76
|
+
mapping_meta = _MappingMeta.for_xml()
|
|
77
|
+
else:
|
|
78
|
+
mapping_meta = _MappingMeta.default()
|
|
79
|
+
|
|
80
|
+
return mapping_meta
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def for_json(cls) -> "_MappingMeta":
|
|
84
|
+
return cls(
|
|
85
|
+
is_blank_node=False,
|
|
86
|
+
blank_node_name="model1",
|
|
87
|
+
blank_node_source=".",
|
|
88
|
+
seperator=".",
|
|
89
|
+
recursive_descent=".",
|
|
90
|
+
model_source_prefix="",
|
|
91
|
+
namespace_seperator=":",
|
|
92
|
+
remove_array_suffix=False,
|
|
93
|
+
check_namespace=False,
|
|
94
|
+
namespace_prefixes={},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def for_xml(cls) -> "_MappingMeta":
|
|
99
|
+
return cls(
|
|
100
|
+
is_blank_node=False,
|
|
101
|
+
blank_node_name="model1",
|
|
102
|
+
blank_node_source=".",
|
|
103
|
+
seperator="/",
|
|
104
|
+
recursive_descent="/..",
|
|
105
|
+
model_source_prefix="/",
|
|
106
|
+
namespace_seperator=":",
|
|
107
|
+
remove_array_suffix=True,
|
|
108
|
+
check_namespace=True,
|
|
109
|
+
namespace_prefixes={"xmlns": ["xmlns", "@xmlns"]},
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def default(cls) -> "_MappingMeta":
|
|
114
|
+
return cls(
|
|
115
|
+
is_blank_node=False,
|
|
116
|
+
blank_node_name="model1",
|
|
117
|
+
blank_node_source=".",
|
|
118
|
+
seperator="",
|
|
119
|
+
recursive_descent="",
|
|
120
|
+
model_source_prefix="",
|
|
121
|
+
namespace_seperator=":",
|
|
122
|
+
remove_array_suffix=False,
|
|
123
|
+
check_namespace=False,
|
|
124
|
+
namespace_prefixes={},
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclasses.dataclass
|
|
129
|
+
class _MappingScope:
|
|
130
|
+
parent_scope: str
|
|
131
|
+
model_scope: str
|
|
132
|
+
model_name: str
|
|
133
|
+
property_name: str
|
spinta/manifests/dict/helpers.py
CHANGED
|
@@ -4,70 +4,59 @@ from copy import deepcopy
|
|
|
4
4
|
|
|
5
5
|
import requests
|
|
6
6
|
import xmltodict
|
|
7
|
-
from typing import
|
|
8
|
-
|
|
9
|
-
from spinta
|
|
7
|
+
from typing import Any, Iterator
|
|
8
|
+
|
|
9
|
+
from spinta import HTTP_URL_PREFIXES
|
|
10
|
+
from spinta.manifests.components import ManifestSchema
|
|
11
|
+
from spinta.manifests.dict.components import (
|
|
12
|
+
DictFormat,
|
|
13
|
+
_MappedDataset,
|
|
14
|
+
_MappingMeta,
|
|
15
|
+
_MappingScope,
|
|
16
|
+
_MappedModels,
|
|
17
|
+
_MappedProperties,
|
|
18
|
+
)
|
|
10
19
|
from spinta.manifests.helpers import TypeDetector
|
|
11
20
|
from spinta.utils.itertools import first_dict_value, first_dict_key
|
|
12
21
|
from spinta.utils.naming import Deduplicator, to_model_name, to_property_name
|
|
13
22
|
|
|
14
23
|
|
|
15
|
-
def read_schema(manifest_type: DictFormat, path: str, dataset_name: str):
|
|
16
|
-
if path.startswith(
|
|
24
|
+
def read_schema(manifest_type: DictFormat, path: str, dataset_name: str) -> Iterator[ManifestSchema]:
|
|
25
|
+
if path.startswith(HTTP_URL_PREFIXES):
|
|
17
26
|
value = requests.get(path).text
|
|
18
27
|
else:
|
|
19
28
|
with pathlib.Path(path).open(encoding="utf-8-sig") as f:
|
|
20
29
|
value = f.read()
|
|
21
30
|
|
|
22
31
|
converted = {}
|
|
23
|
-
mapping_meta = _MappingMeta(
|
|
24
|
-
|
|
25
|
-
blank_node_name="model1",
|
|
26
|
-
blank_node_source=".",
|
|
27
|
-
seperator="",
|
|
28
|
-
recursive_descent="",
|
|
29
|
-
model_source_prefix="",
|
|
30
|
-
namespace_seperator=":",
|
|
31
|
-
remove_array_suffix=False,
|
|
32
|
-
check_namespace=False,
|
|
33
|
-
namespace_prefixes={},
|
|
34
|
-
detect_model=is_model,
|
|
35
|
-
)
|
|
32
|
+
mapping_meta = _MappingMeta.get_for(manifest_type)
|
|
33
|
+
|
|
36
34
|
if manifest_type == DictFormat.JSON:
|
|
37
35
|
converted = json.loads(value)
|
|
38
|
-
mapping_meta["seperator"] = "."
|
|
39
|
-
mapping_meta["recursive_descent"] = "."
|
|
40
|
-
|
|
41
36
|
elif manifest_type in (DictFormat.XML, DictFormat.HTML):
|
|
42
37
|
converted = xmltodict.parse(value, cdata_key="text()")
|
|
43
|
-
mapping_meta["seperator"] = "/"
|
|
44
|
-
mapping_meta["recursive_descent"] = "/.."
|
|
45
|
-
mapping_meta["model_source_prefix"] = "/"
|
|
46
|
-
mapping_meta["remove_array_suffix"] = True
|
|
47
|
-
mapping_meta["check_namespace"] = True
|
|
48
|
-
mapping_meta["namespace_prefixes"] = {"xmlns": ["xmlns", "@xmlns"]}
|
|
49
38
|
|
|
50
39
|
namespaces = list(extract_namespaces(converted, mapping_meta))
|
|
51
40
|
converted = _fix_for_blank_nodes(converted)
|
|
52
41
|
prefixes = {}
|
|
53
42
|
for i, (key, value) in enumerate(namespaces):
|
|
54
43
|
prefixes[key] = {"type": "prefix", "name": key, "uri": value, "eid": i}
|
|
55
|
-
dataset_structure
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
mapping_meta
|
|
44
|
+
dataset_structure = _MappedDataset(
|
|
45
|
+
dataset=dataset_name if dataset_name else "dataset",
|
|
46
|
+
resource="resource",
|
|
47
|
+
models={},
|
|
48
|
+
)
|
|
49
|
+
mapping_meta.is_blank_node = is_blank_node(converted)
|
|
61
50
|
create_type_detectors(dataset_structure, converted, mapping_meta)
|
|
62
51
|
|
|
63
52
|
yield (
|
|
64
53
|
None,
|
|
65
54
|
{
|
|
66
55
|
"type": "dataset",
|
|
67
|
-
"name": dataset_structure
|
|
56
|
+
"name": dataset_structure.dataset,
|
|
68
57
|
"prefixes": prefixes,
|
|
69
58
|
"resources": {
|
|
70
|
-
dataset_structure
|
|
59
|
+
dataset_structure.resource: {
|
|
71
60
|
"type": f"dask/{manifest_type.value}",
|
|
72
61
|
"external": path,
|
|
73
62
|
},
|
|
@@ -78,38 +67,38 @@ def read_schema(manifest_type: DictFormat, path: str, dataset_name: str):
|
|
|
78
67
|
|
|
79
68
|
dedup_model = Deduplicator("{}")
|
|
80
69
|
blank_model = ""
|
|
81
|
-
mapped_models:
|
|
70
|
+
mapped_models: dict[tuple, str] = {}
|
|
82
71
|
|
|
83
|
-
for model in dataset_structure
|
|
72
|
+
for model in dataset_structure.models.values():
|
|
84
73
|
for model_source, m in model.items():
|
|
85
|
-
new_model = to_model_name(_name_without_namespace(m
|
|
74
|
+
new_model = to_model_name(_name_without_namespace(m.name, mapping_meta, prefixes))
|
|
86
75
|
new_model = dedup_model(new_model)
|
|
87
|
-
mapped_models[(m
|
|
76
|
+
mapped_models[(m.name, model_source)] = new_model
|
|
88
77
|
|
|
89
|
-
for model in dataset_structure
|
|
78
|
+
for model in dataset_structure.models.values():
|
|
90
79
|
for model_source, m in model.items():
|
|
91
|
-
if model_source == mapping_meta
|
|
92
|
-
blank_model = mapped_models[(m
|
|
80
|
+
if model_source == mapping_meta.blank_node_source:
|
|
81
|
+
blank_model = mapped_models[(m.name, model_source)]
|
|
93
82
|
dedup_prop = Deduplicator("_{}")
|
|
94
83
|
converted_props = {}
|
|
95
|
-
for prop in m
|
|
96
|
-
new_prop = to_property_name(_name_without_namespace(prop
|
|
84
|
+
for prop in m.properties.values():
|
|
85
|
+
new_prop = to_property_name(_name_without_namespace(prop.name, mapping_meta, prefixes))
|
|
97
86
|
new_prop = dedup_prop(new_prop)
|
|
98
87
|
extra = {}
|
|
99
|
-
type_detector = prop
|
|
88
|
+
type_detector = prop.type_detector
|
|
100
89
|
prop_type = type_detector.get_type()
|
|
101
90
|
if prop_type == "ref":
|
|
102
|
-
if prop
|
|
91
|
+
if prop.name in dataset_structure.models.keys():
|
|
103
92
|
model_name = _name_without_namespace(
|
|
104
|
-
mapped_models[prop
|
|
93
|
+
mapped_models[prop.name, prop.extra], mapping_meta, prefixes
|
|
105
94
|
)
|
|
106
|
-
ref_model = f"{dataset_structure
|
|
95
|
+
ref_model = f"{dataset_structure.dataset}/{model_name}"
|
|
107
96
|
else:
|
|
108
|
-
ref_model = f"{dataset_structure
|
|
97
|
+
ref_model = f"{dataset_structure.dataset}/{blank_model}"
|
|
109
98
|
extra = {"model": ref_model}
|
|
110
99
|
converted_props[new_prop] = {
|
|
111
100
|
"type": prop_type,
|
|
112
|
-
"external": {"name": prop
|
|
101
|
+
"external": {"name": prop.source},
|
|
113
102
|
"description": "",
|
|
114
103
|
"required": type_detector.required,
|
|
115
104
|
"unique": type_detector.unique,
|
|
@@ -122,19 +111,19 @@ def read_schema(manifest_type: DictFormat, path: str, dataset_name: str):
|
|
|
122
111
|
copied["given_name"] = f"{new_prop}[]"
|
|
123
112
|
converted_props[new_prop]["items"] = copied
|
|
124
113
|
|
|
125
|
-
fixed_external_source = m
|
|
126
|
-
if mapping_meta
|
|
114
|
+
fixed_external_source = m.source
|
|
115
|
+
if mapping_meta.remove_array_suffix:
|
|
127
116
|
fixed_external_source = fixed_external_source.replace("[]", "")
|
|
128
117
|
if not fixed_external_source.startswith("."):
|
|
129
|
-
fixed_external_source = f"{mapping_meta
|
|
118
|
+
fixed_external_source = f"{mapping_meta.model_source_prefix}{fixed_external_source}"
|
|
130
119
|
yield (
|
|
131
120
|
None,
|
|
132
121
|
{
|
|
133
122
|
"type": "model",
|
|
134
|
-
"name": f"{dataset_structure
|
|
123
|
+
"name": f"{dataset_structure.dataset}/{mapped_models[(m.name, model_source)]}",
|
|
135
124
|
"external": {
|
|
136
|
-
"dataset": dataset_structure
|
|
137
|
-
"resource": dataset_structure
|
|
125
|
+
"dataset": dataset_structure.dataset,
|
|
126
|
+
"resource": dataset_structure.resource,
|
|
138
127
|
"name": fixed_external_source,
|
|
139
128
|
},
|
|
140
129
|
"description": "",
|
|
@@ -147,80 +136,43 @@ def is_single_item_dict(value: dict) -> bool:
|
|
|
147
136
|
return len(value) == 1
|
|
148
137
|
|
|
149
138
|
|
|
150
|
-
def _fix_for_blank_nodes(values: Any):
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
result = {}
|
|
154
|
-
temp_dict = values
|
|
155
|
-
while is_single_item_dict(temp_dict):
|
|
156
|
-
first_key = first_dict_key(temp_dict)
|
|
157
|
-
temp_dict = temp_dict[first_key]
|
|
158
|
-
|
|
159
|
-
if not isinstance(temp_dict, dict):
|
|
160
|
-
return return_values
|
|
161
|
-
|
|
162
|
-
result[first_key] = temp_dict if is_single_item_dict(temp_dict) else [temp_dict]
|
|
139
|
+
def _fix_for_blank_nodes(values: Any) -> Any:
|
|
140
|
+
if not (isinstance(values, dict) and is_single_item_dict(values)):
|
|
141
|
+
return values
|
|
163
142
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
class _MappedProperties(TypedDict):
|
|
169
|
-
name: str
|
|
170
|
-
source: str
|
|
171
|
-
extra: str
|
|
172
|
-
type_detector: TypeDetector
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
class _MappedModels(TypedDict):
|
|
176
|
-
name: str
|
|
177
|
-
source: str
|
|
178
|
-
properties: Dict[str, _MappedProperties]
|
|
143
|
+
return_values = values
|
|
144
|
+
temp_dict = values
|
|
145
|
+
result = {}
|
|
179
146
|
|
|
147
|
+
while is_single_item_dict(temp_dict):
|
|
148
|
+
first_key = first_dict_key(temp_dict)
|
|
149
|
+
temp_dict = temp_dict[first_key]
|
|
180
150
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
resource: str
|
|
184
|
-
models: Dict[str, Dict[str, _MappedModels]]
|
|
151
|
+
if not isinstance(temp_dict, dict):
|
|
152
|
+
return return_values
|
|
185
153
|
|
|
154
|
+
result[first_key] = temp_dict if is_single_item_dict(temp_dict) else [temp_dict]
|
|
186
155
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
blank_node_name: str
|
|
190
|
-
blank_node_source: str
|
|
191
|
-
seperator: str
|
|
192
|
-
recursive_descent: str
|
|
193
|
-
remove_array_suffix: bool
|
|
194
|
-
model_source_prefix: str
|
|
195
|
-
check_namespace: bool
|
|
196
|
-
namespace_prefixes: dict
|
|
197
|
-
namespace_seperator: str
|
|
198
|
-
detect_model: Callable
|
|
156
|
+
return_values = result
|
|
157
|
+
return return_values
|
|
199
158
|
|
|
200
159
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
model_name: str
|
|
205
|
-
property_name: str
|
|
160
|
+
def _name_without_namespace(name: str, mapping_meta: _MappingMeta, prefixes: dict) -> str:
|
|
161
|
+
if mapping_meta.namespace_seperator not in name:
|
|
162
|
+
return name
|
|
206
163
|
|
|
164
|
+
for prefix in prefixes.keys():
|
|
165
|
+
if (namespace := f"{prefix}{mapping_meta.namespace_seperator}") in name:
|
|
166
|
+
return name.replace(namespace, "")
|
|
207
167
|
|
|
208
|
-
def _name_without_namespace(name: str, mapping_meta: _MappingMeta, prefixes: dict):
|
|
209
|
-
if mapping_meta["namespace_seperator"] in name:
|
|
210
|
-
for prefix in prefixes.keys():
|
|
211
|
-
namespace = f"{prefix}{mapping_meta['namespace_seperator']}"
|
|
212
|
-
if namespace in name:
|
|
213
|
-
return name.replace(namespace, "")
|
|
214
168
|
return name
|
|
215
169
|
|
|
216
170
|
|
|
217
|
-
def is_model(data):
|
|
218
|
-
|
|
219
|
-
return True
|
|
220
|
-
return False
|
|
171
|
+
def is_model(data: Any) -> bool:
|
|
172
|
+
return isinstance(data, list) and is_list_of_dicts(data)
|
|
221
173
|
|
|
222
174
|
|
|
223
|
-
def _find_parent_key(data, string):
|
|
175
|
+
def _find_parent_key(data: dict[str, list[str]], string: str) -> str | None:
|
|
224
176
|
for key, values in data.items():
|
|
225
177
|
for value in values:
|
|
226
178
|
if string.startswith(value):
|
|
@@ -228,29 +180,33 @@ def _find_parent_key(data, string):
|
|
|
228
180
|
return None
|
|
229
181
|
|
|
230
182
|
|
|
231
|
-
def extract_namespaces(data: Any, mapping_meta: _MappingMeta):
|
|
232
|
-
if mapping_meta
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
183
|
+
def extract_namespaces(data: Any, mapping_meta: _MappingMeta) -> Iterator[Any]:
|
|
184
|
+
if not mapping_meta.check_namespace:
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
if isinstance(data, dict):
|
|
188
|
+
keys_to_remove = {}
|
|
189
|
+
for key, value in data.items():
|
|
190
|
+
parent = _find_parent_key(mapping_meta.namespace_prefixes, key)
|
|
191
|
+
if parent is not None and key not in keys_to_remove.keys():
|
|
192
|
+
return_key = key.split(mapping_meta.namespace_seperator)
|
|
193
|
+
if len(return_key) == 1:
|
|
194
|
+
return_key = [parent]
|
|
195
|
+
keys_to_remove[key] = (return_key[-1], value)
|
|
196
|
+
|
|
197
|
+
for key, value in keys_to_remove.items():
|
|
198
|
+
del data[key]
|
|
199
|
+
yield value
|
|
200
|
+
|
|
201
|
+
for value in data.values():
|
|
202
|
+
yield from extract_namespaces(value, mapping_meta)
|
|
203
|
+
|
|
204
|
+
elif isinstance(data, list):
|
|
205
|
+
for item in data:
|
|
206
|
+
yield from extract_namespaces(item, mapping_meta)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def nested_prop_names(new_values: list, values: dict, root: str, seperator: str) -> None:
|
|
254
210
|
for key, value in values.items():
|
|
255
211
|
if isinstance(value, dict):
|
|
256
212
|
nested_prop_names(new_values, value, f"{root}{seperator}{key}", seperator)
|
|
@@ -263,136 +219,150 @@ def nested_prop_names(new_values: list, values: dict, root: str, seperator: str)
|
|
|
263
219
|
|
|
264
220
|
def check_missing_prop_required(
|
|
265
221
|
dataset: _MappedDataset, values: dict, mapping_scope: _MappingScope, mapping_meta: _MappingMeta
|
|
266
|
-
):
|
|
267
|
-
if mapping_scope
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
key_values = []
|
|
276
|
-
for k, v in values.items():
|
|
277
|
-
new_val = _create_name_with_prefix(mapping_scope["model_scope"], mapping_meta["seperator"], k)
|
|
278
|
-
if isinstance(v, dict):
|
|
279
|
-
nested_prop_names(key_values, v, new_val, mapping_meta["seperator"])
|
|
280
|
-
elif isinstance(v, list):
|
|
281
|
-
if not is_list_of_dicts(v):
|
|
282
|
-
key_values.append(new_val)
|
|
283
|
-
else:
|
|
284
|
-
key_values.append(new_val)
|
|
285
|
-
if key_values:
|
|
286
|
-
filtered_models = dataset["models"][model_name][model_source]["properties"].keys()
|
|
287
|
-
subtracted = set(filtered_models) - set(key_values)
|
|
288
|
-
for prop in subtracted:
|
|
289
|
-
type_detector = dataset["models"][model_name][model_source]["properties"][prop]["type_detector"]
|
|
290
|
-
if type_detector.required and type_detector.type != "ref":
|
|
291
|
-
type_detector.required = False
|
|
222
|
+
) -> None:
|
|
223
|
+
if mapping_scope.model_scope != "":
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
model_name = mapping_scope.model_name if mapping_scope.model_name != "" else first_dict_key(dataset.models)
|
|
227
|
+
model_source = _create_name_with_prefix(mapping_scope.parent_scope, mapping_meta.seperator, model_name)
|
|
228
|
+
if mapping_scope.model_name == "" and mapping_meta.is_blank_node:
|
|
229
|
+
model_name = mapping_meta.blank_node_name
|
|
230
|
+
model_source = mapping_meta.blank_node_source
|
|
292
231
|
|
|
232
|
+
key_values = []
|
|
233
|
+
for key, value in values.items():
|
|
234
|
+
new_value = _create_name_with_prefix(mapping_scope.model_scope, mapping_meta.seperator, key)
|
|
235
|
+
if isinstance(value, dict):
|
|
236
|
+
nested_prop_names(key_values, value, new_value, mapping_meta.seperator)
|
|
237
|
+
elif isinstance(value, list):
|
|
238
|
+
if not is_list_of_dicts(value):
|
|
239
|
+
key_values.append(new_value)
|
|
240
|
+
else:
|
|
241
|
+
key_values.append(new_value)
|
|
242
|
+
|
|
243
|
+
if not key_values:
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
filtered_models = dataset.models[model_name][model_source].properties.keys()
|
|
247
|
+
subtracted = set(filtered_models) - set(key_values)
|
|
248
|
+
for prop in subtracted:
|
|
249
|
+
type_detector = dataset.models[model_name][model_source].properties[prop].type_detector
|
|
250
|
+
if type_detector.required and type_detector.type != "ref":
|
|
251
|
+
type_detector.required = False
|
|
293
252
|
|
|
294
|
-
|
|
253
|
+
|
|
254
|
+
def run_type_detectors(
|
|
255
|
+
dataset: _MappedDataset, values: dict, mapping_scope: _MappingScope, mapping_meta: _MappingMeta
|
|
256
|
+
) -> None:
|
|
295
257
|
if isinstance(values, list):
|
|
296
258
|
for item in values:
|
|
297
259
|
run_type_detectors(dataset, item, mapping_scope, mapping_meta)
|
|
260
|
+
|
|
298
261
|
elif isinstance(values, dict):
|
|
299
262
|
check_missing_prop_required(dataset, values, mapping_scope, mapping_meta)
|
|
300
263
|
for key, value in values.items():
|
|
301
|
-
|
|
302
|
-
parent_scope=mapping_scope["parent_scope"],
|
|
303
|
-
model_name=mapping_scope["model_name"],
|
|
304
|
-
model_scope=mapping_scope["model_scope"],
|
|
305
|
-
property_name=key,
|
|
306
|
-
)
|
|
307
|
-
if mapping_meta["detect_model"](value):
|
|
308
|
-
new_mapping_scope["model_name"] = key
|
|
264
|
+
if is_model(value):
|
|
309
265
|
parent_scope = _create_name_with_prefix(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
266
|
+
prefix=_create_name_with_prefix(
|
|
267
|
+
prefix=mapping_scope.parent_scope,
|
|
268
|
+
seperator=mapping_meta.seperator,
|
|
269
|
+
value="" if mapping_scope.model_name == "" else f"{mapping_scope.model_name}[]",
|
|
270
|
+
),
|
|
271
|
+
seperator=mapping_meta.seperator,
|
|
272
|
+
value=mapping_scope.model_scope,
|
|
313
273
|
)
|
|
314
|
-
|
|
315
|
-
parent_scope,
|
|
274
|
+
new_mapping_scope = _MappingScope(
|
|
275
|
+
parent_scope=parent_scope,
|
|
276
|
+
model_name=key,
|
|
277
|
+
model_scope="",
|
|
278
|
+
property_name=key,
|
|
316
279
|
)
|
|
317
|
-
new_mapping_scope["model_scope"] = ""
|
|
318
|
-
new_mapping_scope["parent_scope"] = parent_scope
|
|
319
280
|
run_type_detectors(dataset, value, new_mapping_scope, mapping_meta)
|
|
320
281
|
else:
|
|
282
|
+
new_mapping_scope = _MappingScope(
|
|
283
|
+
parent_scope=mapping_scope.parent_scope,
|
|
284
|
+
model_name=mapping_scope.model_name,
|
|
285
|
+
model_scope=mapping_scope.model_scope,
|
|
286
|
+
property_name=key,
|
|
287
|
+
)
|
|
321
288
|
if isinstance(value, dict):
|
|
322
|
-
new_mapping_scope
|
|
323
|
-
new_mapping_scope
|
|
289
|
+
new_mapping_scope.model_scope = _create_name_with_prefix(
|
|
290
|
+
prefix=new_mapping_scope.model_scope,
|
|
291
|
+
seperator=mapping_meta.seperator,
|
|
292
|
+
value=key,
|
|
324
293
|
)
|
|
325
294
|
run_type_detectors(dataset, value, new_mapping_scope, mapping_meta)
|
|
326
295
|
else:
|
|
327
296
|
_detect_type(dataset, new_mapping_scope, mapping_meta, value)
|
|
328
297
|
|
|
329
298
|
|
|
330
|
-
def _detect_type(dataset: _MappedDataset, mapping_scope: _MappingScope, mapping_meta: _MappingMeta, value: Any):
|
|
331
|
-
prop_name = _create_name_with_prefix(
|
|
332
|
-
|
|
333
|
-
)
|
|
334
|
-
model_name = mapping_scope["model_name"]
|
|
299
|
+
def _detect_type(dataset: _MappedDataset, mapping_scope: _MappingScope, mapping_meta: _MappingMeta, value: Any) -> None:
|
|
300
|
+
prop_name = _create_name_with_prefix(mapping_scope.model_scope, mapping_meta.seperator, mapping_scope.property_name)
|
|
301
|
+
model_name = mapping_scope.model_name
|
|
335
302
|
model_source = _create_name_with_prefix(
|
|
336
|
-
mapping_scope
|
|
303
|
+
mapping_scope.parent_scope, mapping_meta.seperator, mapping_scope.model_name
|
|
337
304
|
)
|
|
338
305
|
if model_name == "":
|
|
339
|
-
model_name = mapping_meta
|
|
340
|
-
model_source = mapping_meta
|
|
341
|
-
dataset
|
|
306
|
+
model_name = mapping_meta.blank_node_name
|
|
307
|
+
model_source = mapping_meta.blank_node_source
|
|
308
|
+
dataset.models[model_name][model_source].properties[prop_name].type_detector.detect(value)
|
|
342
309
|
|
|
343
310
|
|
|
344
|
-
def is_list_of_dicts(
|
|
345
|
-
for item in
|
|
346
|
-
if not isinstance(item, dict):
|
|
347
|
-
return False
|
|
348
|
-
return True
|
|
311
|
+
def is_list_of_dicts(data: list) -> bool:
|
|
312
|
+
return all(isinstance(item, dict) for item in data)
|
|
349
313
|
|
|
350
314
|
|
|
351
315
|
def setup_model_type_detectors(
|
|
352
|
-
dataset: _MappedDataset, values:
|
|
353
|
-
):
|
|
316
|
+
dataset: _MappedDataset, values: dict | list, mapping_scope: _MappingScope, mapping_meta: _MappingMeta
|
|
317
|
+
) -> None:
|
|
354
318
|
if isinstance(values, list):
|
|
355
319
|
for item in values:
|
|
356
320
|
setup_model_type_detectors(dataset, item, mapping_scope, mapping_meta)
|
|
321
|
+
|
|
357
322
|
elif isinstance(values, dict):
|
|
358
323
|
for key, value in values.items():
|
|
359
|
-
|
|
360
|
-
parent_scope=mapping_scope["parent_scope"],
|
|
361
|
-
model_name=mapping_scope["model_name"],
|
|
362
|
-
model_scope=mapping_scope["model_scope"],
|
|
363
|
-
property_name=key,
|
|
364
|
-
)
|
|
365
|
-
if mapping_meta["detect_model"](value):
|
|
366
|
-
new_mapping_scope["model_name"] = key
|
|
324
|
+
if is_model(value):
|
|
367
325
|
parent_scope = _create_name_with_prefix(
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
326
|
+
prefix=_create_name_with_prefix(
|
|
327
|
+
prefix=mapping_scope.parent_scope,
|
|
328
|
+
seperator=mapping_meta.seperator,
|
|
329
|
+
value="" if mapping_scope.model_name == "" else f"{mapping_scope.model_name}[]",
|
|
330
|
+
),
|
|
331
|
+
seperator=mapping_meta.seperator,
|
|
332
|
+
value=mapping_scope.model_scope,
|
|
371
333
|
)
|
|
372
|
-
parent_scope = _create_name_with_prefix(
|
|
373
|
-
parent_scope, mapping_meta["seperator"], new_mapping_scope["model_scope"]
|
|
374
|
-
)
|
|
375
|
-
new_mapping_scope["model_scope"] = ""
|
|
376
|
-
new_mapping_scope["parent_scope"] = parent_scope
|
|
377
334
|
|
|
335
|
+
new_mapping_scope = _MappingScope(
|
|
336
|
+
parent_scope=parent_scope,
|
|
337
|
+
model_name=key,
|
|
338
|
+
model_scope="",
|
|
339
|
+
property_name=key,
|
|
340
|
+
)
|
|
378
341
|
setup_model_type_detectors(dataset, value, new_mapping_scope, mapping_meta)
|
|
379
342
|
|
|
380
|
-
old_mapping_scope = new_mapping_scope
|
|
381
|
-
old_mapping_scope
|
|
343
|
+
old_mapping_scope = deepcopy(new_mapping_scope)
|
|
344
|
+
old_mapping_scope.property_name = mapping_scope.property_name
|
|
382
345
|
|
|
383
|
-
if old_mapping_scope
|
|
384
|
-
old_mapping_scope
|
|
346
|
+
if old_mapping_scope.property_name == "" and mapping_meta.is_blank_node:
|
|
347
|
+
old_mapping_scope.property_name = "parent"
|
|
385
348
|
set_type_detector(dataset, old_mapping_scope, mapping_meta, is_ref=True)
|
|
386
|
-
elif old_mapping_scope
|
|
349
|
+
elif old_mapping_scope.property_name != "":
|
|
387
350
|
set_type_detector(dataset, old_mapping_scope, mapping_meta, is_ref=True)
|
|
351
|
+
|
|
388
352
|
else:
|
|
353
|
+
new_mapping_scope = _MappingScope(
|
|
354
|
+
parent_scope=mapping_scope.parent_scope,
|
|
355
|
+
model_name=mapping_scope.model_name,
|
|
356
|
+
model_scope=mapping_scope.model_scope,
|
|
357
|
+
property_name=key,
|
|
358
|
+
)
|
|
389
359
|
if isinstance(value, list):
|
|
390
360
|
set_type_detector(dataset, new_mapping_scope, mapping_meta, is_array=True)
|
|
391
361
|
elif isinstance(value, dict):
|
|
392
|
-
new_mapping_scope
|
|
393
|
-
new_mapping_scope
|
|
362
|
+
new_mapping_scope.model_scope = _create_name_with_prefix(
|
|
363
|
+
new_mapping_scope.model_scope, mapping_meta.seperator, key
|
|
394
364
|
)
|
|
395
|
-
new_mapping_scope
|
|
365
|
+
new_mapping_scope.property_name = mapping_scope.property_name
|
|
396
366
|
setup_model_type_detectors(dataset, value, new_mapping_scope, mapping_meta)
|
|
397
367
|
else:
|
|
398
368
|
set_type_detector(dataset, new_mapping_scope, mapping_meta)
|
|
@@ -401,18 +371,22 @@ def setup_model_type_detectors(
|
|
|
401
371
|
def _create_name_with_prefix(prefix: str, seperator: str, value: str) -> str:
|
|
402
372
|
if value == "":
|
|
403
373
|
return prefix
|
|
404
|
-
|
|
374
|
+
if prefix == "":
|
|
375
|
+
return value
|
|
376
|
+
|
|
377
|
+
return f"{prefix}{seperator}{value}"
|
|
405
378
|
|
|
406
379
|
|
|
407
|
-
def create_type_detectors(dataset: _MappedDataset, values: Any, mapping_meta: _MappingMeta):
|
|
380
|
+
def create_type_detectors(dataset: _MappedDataset, values: Any, mapping_meta: _MappingMeta) -> None:
|
|
408
381
|
mapping_scope = _MappingScope(parent_scope="", model_scope="", model_name="", property_name="")
|
|
409
382
|
setup_model_type_detectors(dataset, values, mapping_scope, mapping_meta)
|
|
410
383
|
run_type_detectors(dataset, values, mapping_scope, mapping_meta)
|
|
411
384
|
|
|
412
385
|
|
|
413
|
-
def is_blank_node(values:
|
|
386
|
+
def is_blank_node(values: list | dict) -> bool:
|
|
414
387
|
if isinstance(values, list):
|
|
415
388
|
return True
|
|
389
|
+
|
|
416
390
|
if isinstance(values, dict):
|
|
417
391
|
temp_dict = values
|
|
418
392
|
first_value = first_dict_value(temp_dict)
|
|
@@ -429,6 +403,7 @@ def is_blank_node(values: Union[list, dict]) -> bool:
|
|
|
429
403
|
for key, value in values.items():
|
|
430
404
|
if not isinstance(value, list):
|
|
431
405
|
return True
|
|
406
|
+
|
|
432
407
|
return False
|
|
433
408
|
|
|
434
409
|
|
|
@@ -438,75 +413,74 @@ def set_type_detector(
|
|
|
438
413
|
mapping_meta: _MappingMeta,
|
|
439
414
|
is_ref: bool = False,
|
|
440
415
|
is_array: bool = False,
|
|
441
|
-
):
|
|
442
|
-
if mapping_scope
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if
|
|
467
|
-
if
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
else:
|
|
476
|
-
dataset["models"][model_name][model_source] = {
|
|
477
|
-
"name": model_name,
|
|
478
|
-
"source": model_source,
|
|
479
|
-
"properties": {
|
|
480
|
-
prop_name: {
|
|
481
|
-
"name": prop_name,
|
|
482
|
-
"source": prop_source,
|
|
483
|
-
"type_detector": TypeDetector(),
|
|
484
|
-
"extra": extra,
|
|
485
|
-
}
|
|
486
|
-
},
|
|
487
|
-
}
|
|
416
|
+
) -> None:
|
|
417
|
+
if mapping_scope.property_name == "":
|
|
418
|
+
return
|
|
419
|
+
|
|
420
|
+
model_name = mapping_scope.model_name
|
|
421
|
+
model_source = _create_name_with_prefix(mapping_scope.parent_scope, mapping_meta.seperator, model_name)
|
|
422
|
+
prop_name = _create_name_with_prefix(mapping_scope.model_scope, mapping_meta.seperator, mapping_scope.property_name)
|
|
423
|
+
prop_source = prop_name
|
|
424
|
+
if model_name == "" and mapping_meta.is_blank_node:
|
|
425
|
+
model_name = mapping_meta.blank_node_name
|
|
426
|
+
model_source = mapping_meta.blank_node_source
|
|
427
|
+
extra = ""
|
|
428
|
+
if is_ref:
|
|
429
|
+
split = mapping_scope.parent_scope.split(mapping_meta.seperator)
|
|
430
|
+
count = 0
|
|
431
|
+
for i in reversed(split):
|
|
432
|
+
if i.endswith("[]"):
|
|
433
|
+
half = mapping_scope.parent_scope.split(i)
|
|
434
|
+
extra = i[:-2] if half[0] == "" else f"{half[0]}{i[:-2]}"
|
|
435
|
+
break
|
|
436
|
+
elif i != "":
|
|
437
|
+
count += 1
|
|
438
|
+
prop_source = f"..{mapping_meta.recursive_descent * count}"
|
|
439
|
+
|
|
440
|
+
if model_name in dataset.models.keys():
|
|
441
|
+
if model_source in dataset.models[model_name].keys():
|
|
442
|
+
if prop_name not in dataset.models[model_name][model_source].properties.keys():
|
|
443
|
+
dataset.models[model_name][model_source].properties[prop_name] = _MappedProperties(
|
|
444
|
+
name=prop_name,
|
|
445
|
+
source=prop_source,
|
|
446
|
+
type_detector=TypeDetector(),
|
|
447
|
+
extra=extra,
|
|
448
|
+
)
|
|
488
449
|
else:
|
|
489
|
-
dataset
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
prop_name
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
450
|
+
dataset.models[model_name][model_source] = _MappedModels(
|
|
451
|
+
name=model_name,
|
|
452
|
+
source=model_source,
|
|
453
|
+
properties={
|
|
454
|
+
prop_name: _MappedProperties(
|
|
455
|
+
name=prop_name,
|
|
456
|
+
source=prop_source,
|
|
457
|
+
type_detector=TypeDetector(),
|
|
458
|
+
extra=extra,
|
|
459
|
+
)
|
|
460
|
+
},
|
|
461
|
+
)
|
|
462
|
+
else:
|
|
463
|
+
dataset.models[model_name] = {
|
|
464
|
+
model_source: _MappedModels(
|
|
465
|
+
name=model_name,
|
|
466
|
+
source=model_source,
|
|
467
|
+
properties={
|
|
468
|
+
prop_name: _MappedProperties(
|
|
469
|
+
name=prop_name,
|
|
470
|
+
source=prop_source,
|
|
471
|
+
type_detector=TypeDetector(),
|
|
472
|
+
extra=extra,
|
|
473
|
+
)
|
|
474
|
+
},
|
|
475
|
+
)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
type_detector = dataset.models[model_name][model_source].properties[prop_name].type_detector
|
|
479
|
+
if is_array:
|
|
480
|
+
type_detector.array = True
|
|
481
|
+
type_detector.unique = False
|
|
482
|
+
type_detector.required = False
|
|
483
|
+
if is_ref:
|
|
484
|
+
type_detector.type = "ref"
|
|
485
|
+
type_detector.unique = False
|
|
486
|
+
type_detector.required = False
|
spinta/manifests/helpers.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing import Type
|
|
|
8
8
|
|
|
9
9
|
import jsonpatch
|
|
10
10
|
|
|
11
|
-
from spinta import commands
|
|
11
|
+
from spinta import commands, HTTP_URL_PREFIXES
|
|
12
12
|
from spinta.backends.constants import BackendOrigin
|
|
13
13
|
from spinta.backends.helpers import load_backend
|
|
14
14
|
from spinta.components import Model
|
|
@@ -324,7 +324,7 @@ def get_manifest_from_type(rc: RawConfig, type_: str) -> Type[Manifest]:
|
|
|
324
324
|
|
|
325
325
|
|
|
326
326
|
def check_manifest_path(manifest: Manifest, path: str) -> None:
|
|
327
|
-
if not path.startswith(
|
|
327
|
+
if not path.startswith(HTTP_URL_PREFIXES) and not pathlib.Path(path).exists():
|
|
328
328
|
raise ManifestFileDoesNotExist(manifest, path=path)
|
|
329
329
|
|
|
330
330
|
|
|
@@ -432,7 +432,7 @@ class TypeDetector:
|
|
|
432
432
|
self.type = new_type
|
|
433
433
|
|
|
434
434
|
def _assert_url(self, value: str):
|
|
435
|
-
if value.startswith(
|
|
435
|
+
if value.startswith(HTTP_URL_PREFIXES):
|
|
436
436
|
self.type = "url"
|
|
437
437
|
else:
|
|
438
438
|
self.type = ""
|
spinta/manifests/sql/helpers.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import dataclasses
|
|
2
|
+
import logging
|
|
2
3
|
from operator import itemgetter
|
|
3
4
|
from typing import Any, TypedDict
|
|
4
5
|
from typing import Dict
|
|
@@ -28,6 +29,9 @@ from spinta.utils.naming import to_model_name
|
|
|
28
29
|
from spinta.utils.naming import to_property_name
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
31
35
|
def read_schema(context: Context, path: str, prepare: str = None, dataset_name: str = ""):
|
|
32
36
|
engine = sa.create_engine(path)
|
|
33
37
|
schema = None
|
|
@@ -236,6 +240,7 @@ def _read_props(
|
|
|
236
240
|
)
|
|
237
241
|
|
|
238
242
|
|
|
243
|
+
UNKNOWN_TYPE = "UNKNOWN"
|
|
239
244
|
TYPES = [
|
|
240
245
|
(sa.Boolean, "boolean"),
|
|
241
246
|
(sa.Date, "date"),
|
|
@@ -273,12 +278,13 @@ class _Column(TypedDict):
|
|
|
273
278
|
type: TypeEngine
|
|
274
279
|
|
|
275
280
|
|
|
276
|
-
def _get_column_type(column: _Column, table: str = None) -> str:
|
|
281
|
+
def _get_column_type(column: _Column, table: str | None = None) -> str:
|
|
277
282
|
column_type: TypeEngine = column["type"]
|
|
278
283
|
for cls, name in TYPES:
|
|
279
284
|
if isinstance(column_type, cls):
|
|
280
285
|
return name
|
|
281
|
-
|
|
286
|
+
logger.warning(f"Unknown type {column_type!r} of column {column!r} in table {table!r}. Column will be skipped.")
|
|
287
|
+
return UNKNOWN_TYPE
|
|
282
288
|
|
|
283
289
|
|
|
284
290
|
class _Ref(NamedTuple):
|
spinta/nodes.py
CHANGED
|
@@ -14,6 +14,7 @@ from spinta.components import Context
|
|
|
14
14
|
from spinta.components import EntryId
|
|
15
15
|
from spinta.components import Node
|
|
16
16
|
from spinta.manifests.components import Manifest
|
|
17
|
+
from spinta.manifests.sql.helpers import UNKNOWN_TYPE
|
|
17
18
|
from spinta.manifests.tabular.constants import DataTypeEnum
|
|
18
19
|
from spinta.utils.schema import NA
|
|
19
20
|
from spinta.utils.schema import resolve_schema
|
|
@@ -221,6 +222,9 @@ def load_model_properties(
|
|
|
221
222
|
model.leafprops = {}
|
|
222
223
|
model.properties = {}
|
|
223
224
|
for name, params in data.items():
|
|
225
|
+
# Do not load properties with unmapped types.
|
|
226
|
+
if params["type"] == UNKNOWN_TYPE:
|
|
227
|
+
continue
|
|
224
228
|
prop = Prop()
|
|
225
229
|
prop.name = name
|
|
226
230
|
prop.place = name
|
spinta/testing/pytest.py
CHANGED
|
@@ -97,8 +97,12 @@ def mongo(rc):
|
|
|
97
97
|
if dsn and db:
|
|
98
98
|
import pymongo
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
try:
|
|
101
|
+
client = pymongo.MongoClient(dsn, serverSelectionTimeoutMS=2000)
|
|
102
|
+
client.server_info() # force connection check
|
|
103
|
+
client.drop_database(db)
|
|
104
|
+
except pymongo.errors.ServerSelectionTimeoutError:
|
|
105
|
+
pass # MongoDB not running, nothing to clean up
|
|
102
106
|
|
|
103
107
|
|
|
104
108
|
@pytest.fixture(scope="session")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
spinta/__init__.py,sha256=
|
|
1
|
+
spinta/__init__.py,sha256=OLVp_IMRnqoX_Bxzh2exv1p4N0NSTPTBVVjhX74qFCU,123
|
|
2
2
|
spinta/__main__.py,sha256=3n1t_DsFmpQZyAtqPrfXyHAPjpBoS-Oj9hPPFSi2IPw,70
|
|
3
3
|
spinta/accesslog/__init__.py,sha256=svgEqf0U1ykvxQ61pRuAzadwdn7TnQriQ4a9A_aMoKI,5938
|
|
4
4
|
spinta/accesslog/file.py,sha256=h1KcGsbIPoI2ZzXXQ2b8eZFOP0EvkTudfWDmwy25zlg,2150
|
|
@@ -107,7 +107,7 @@ spinta/backends/postgresql/commands/migrate/types/string.py,sha256=C2jo9AH8YTLlc
|
|
|
107
107
|
spinta/backends/postgresql/commands/migrate/types/text.py,sha256=E8Pa4GpCIq2JLNRxkkF5YIs4hfpqy4AVQgGXAfplzoI,5767
|
|
108
108
|
spinta/backends/postgresql/commands/read.py,sha256=h_kMFdb3-wl5i-3yh6b4dr-09GVNgUos65NDWMf0Igk,2908
|
|
109
109
|
spinta/backends/postgresql/commands/redirect.py,sha256=nc1cHobA3JsmXn3h5otKNIU-a1us3ouTNKjhr6N7zMk,1810
|
|
110
|
-
spinta/backends/postgresql/commands/summary.py,sha256=
|
|
110
|
+
spinta/backends/postgresql/commands/summary.py,sha256=bwbLVMB1MVAHpGrRRLy38PpNedUt-se3AHx4pdhQjX4,17585
|
|
111
111
|
spinta/backends/postgresql/commands/validate.py,sha256=Q6NEK3vIkd1k4jLg9pGRKKw6PfelS52m-BORGg4nO_Y,615
|
|
112
112
|
spinta/backends/postgresql/commands/wait.py,sha256=Yr_NF3hprX-KhKAqRcddrnRJZazsCWud3yYYI1fi2yg,647
|
|
113
113
|
spinta/backends/postgresql/commands/wipe.py,sha256=o0mZuYVr5xbQfO3lqxpBcVtiZE0FqOJyAm738XGf36Q,2279
|
|
@@ -522,9 +522,9 @@ spinta/manifests/dict/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
522
522
|
spinta/manifests/dict/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
523
523
|
spinta/manifests/dict/commands/configure.py,sha256=P74uhCZKdr6nc70gBBkr1tvsrv5JjKowMx7QQMwzJVA,537
|
|
524
524
|
spinta/manifests/dict/commands/load.py,sha256=eILuiDz5mSrB93fdxseYl8gZNUtUXwVnQJQ06CatrTg,1417
|
|
525
|
-
spinta/manifests/dict/components.py,sha256=
|
|
526
|
-
spinta/manifests/dict/helpers.py,sha256=
|
|
527
|
-
spinta/manifests/helpers.py,sha256=
|
|
525
|
+
spinta/manifests/dict/components.py,sha256=fY7IKoArTrPhKaMukwXYP3IfYdJETHRzhUaNrAt4xWs,3281
|
|
526
|
+
spinta/manifests/dict/helpers.py,sha256=AzLQMMdvwvcAb7XWgmJtvDgVEyazN0GgPS9A6DRX3oo,19235
|
|
527
|
+
spinta/manifests/helpers.py,sha256=k_QBpWeWeMTIA9oSN-y5QjUcwJV8-CEL1fVJCGqAKGI,14618
|
|
528
528
|
spinta/manifests/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
529
529
|
spinta/manifests/internal/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
530
530
|
spinta/manifests/internal/commands/configure.py,sha256=pNSEwita8LCnn1r7Xs6BiijEd9LW8kqa24oIjeDAP-Y,462
|
|
@@ -567,7 +567,7 @@ spinta/manifests/sql/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
|
567
567
|
spinta/manifests/sql/commands/configure.py,sha256=j_ypYAV9o0pTS_qazw1oBCuRohSXfGPs_tmrDUIEVNk,539
|
|
568
568
|
spinta/manifests/sql/commands/load.py,sha256=xHdoo7dWHZ9RtCUo7J0R89DyFFFUKG7XV-0vVgE9SHo,1806
|
|
569
569
|
spinta/manifests/sql/components.py,sha256=lG44u_ufsqDm3kjP8_zshYg87J5S_UVzYWJ5Ea74G1w,661
|
|
570
|
-
spinta/manifests/sql/helpers.py,sha256=
|
|
570
|
+
spinta/manifests/sql/helpers.py,sha256=LgnWWU4P2UMVC9zp0Dpwk_5ZnLCXQnlPWv4Jp8aApk8,14853
|
|
571
571
|
spinta/manifests/tabular/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
572
572
|
spinta/manifests/tabular/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
573
573
|
spinta/manifests/tabular/commands/bootstrap.py,sha256=hdINMkcwBKXlpKPPXXJqdMjWpLb5WEigf-RfEFcEUkE,438
|
|
@@ -610,7 +610,7 @@ spinta/naming/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
610
610
|
spinta/naming/components.py,sha256=TnuJg3fB9ftLOV6C2QI2lI-e3_OhlFdpI-qWW0wDeS4,210
|
|
611
611
|
spinta/naming/helpers.py,sha256=tmey39J56_4YQ-jvsVInon4NJkyzM6i91hN_RMtt9kM,4599
|
|
612
612
|
spinta/naming/ufuncts.py,sha256=gRGgyt_jjqn0-QHLc7BWGtJRb4qdaBCc8I90mdzJeYc,1334
|
|
613
|
-
spinta/nodes.py,sha256=
|
|
613
|
+
spinta/nodes.py,sha256=UQJU0rQK2avVUkvQ6oXz3GQkZIvVAd0zaXJQpp5XTlg,8070
|
|
614
614
|
spinta/renderer.py,sha256=D0hlDOFFdjfjZ4x6WV9pK5Lozs0fbpLYd-IcOmtNoR0,761
|
|
615
615
|
spinta/spyna.py,sha256=lwBjhpxKoZtnEMmIvvGlCy0yLKfqmU575F-Axr2K5t4,11528
|
|
616
616
|
spinta/templates/base.html,sha256=tRMf48yngJ-zPDP9mP-Q9TkQW4VXIXkdqpodzwFGF0w,2092
|
|
@@ -629,7 +629,7 @@ spinta/testing/dtypes.py,sha256=5qGBuCjDJywTJSvJmvA62DvY8H-dJFti441wtGkrvO0,6288
|
|
|
629
629
|
spinta/testing/manifest.py,sha256=HCrgCu9QMry_iNtuGkQI7-hp6m5xmtSMUTzwpW0Z6y8,6121
|
|
630
630
|
spinta/testing/migration.py,sha256=q-fQqjTtTZKdJKagYFYAspkGQHhenYoO4O2x-Amamdw,7979
|
|
631
631
|
spinta/testing/push.py,sha256=t_2PpWQI-95_rNUhvBZTHtOQhaIpTO0nXHd5nigI6mM,531
|
|
632
|
-
spinta/testing/pytest.py,sha256=
|
|
632
|
+
spinta/testing/pytest.py,sha256=ouXo_G8N3IEGAQZ74YlJhAzW7KPbv-20_6a0bc1OeXY,10492
|
|
633
633
|
spinta/testing/request.py,sha256=vJ5uJASCE21w9WFwvYaB5zDHfL3d744LNwLi6kk8fXQ,2605
|
|
634
634
|
spinta/testing/tabular.py,sha256=_AEi6Lf_rcIlWO-55XfAYx-1sdHSBtyFMlsXGg1C8DE,1114
|
|
635
635
|
spinta/testing/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -748,8 +748,8 @@ spinta/utils/tree.py,sha256=iF8eOSBagUoDmdJGNQgsYB_gshsFajmiUALXqU9luHE,591
|
|
|
748
748
|
spinta/utils/types.py,sha256=lfYSxKGPuPeUsO14d2OYodtbRY3zsa-o-z8HveVH3t0,801
|
|
749
749
|
spinta/utils/units.py,sha256=CFFLv1NHYsoSSzwiar3zXYmt4m3sccW5niUgkZQgo3k,747
|
|
750
750
|
spinta/utils/url.py,sha256=b6sqQEpmCdT3oV4vGDzXnN8w415InAYjIW_o2djhQS8,2950
|
|
751
|
-
spinta-0.2.
|
|
752
|
-
spinta-0.2.
|
|
753
|
-
spinta-0.2.
|
|
754
|
-
spinta-0.2.
|
|
755
|
-
spinta-0.2.
|
|
751
|
+
spinta-0.2.dev19.dist-info/METADATA,sha256=uWFAtzdrYe0mMg-4oVZH6LKnB9hB8aG-cdhgK62AqIY,10207
|
|
752
|
+
spinta-0.2.dev19.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
753
|
+
spinta-0.2.dev19.dist-info/entry_points.txt,sha256=-jdsOQZcMu3rUOwgIJNS3gZS4rwWPACuXXy128F676w,46
|
|
754
|
+
spinta-0.2.dev19.dist-info/licenses/LICENSE,sha256=JKmjfBLapeFWNI_qdVr5bXGlsuMPa6nRarKPK5davKw,1071
|
|
755
|
+
spinta-0.2.dev19.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|