elody 0.0.155__py3-none-any.whl → 0.0.157__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.
- elody/csv.py +9 -2
- elody/object_configurations/base_object_configuration.py +50 -25
- elody/object_configurations/elody_configuration.py +66 -22
- elody/object_configurations/job_configuration.py +2 -2
- elody/policies/permission_handler.py +18 -8
- {elody-0.0.155.dist-info → elody-0.0.157.dist-info}/METADATA +2 -2
- {elody-0.0.155.dist-info → elody-0.0.157.dist-info}/RECORD +12 -12
- tests/unit/test_csv.py +58 -4
- tests/unit/test_utils.py +3 -1
- {elody-0.0.155.dist-info → elody-0.0.157.dist-info}/LICENSE +0 -0
- {elody-0.0.155.dist-info → elody-0.0.157.dist-info}/WHEEL +0 -0
- {elody-0.0.155.dist-info → elody-0.0.157.dist-info}/top_level.txt +0 -0
elody/csv.py
CHANGED
|
@@ -185,14 +185,21 @@ class CSVMultiObject(CSVParser):
|
|
|
185
185
|
indexed_dict = dict()
|
|
186
186
|
external_mediafiles_ids = []
|
|
187
187
|
for row in self.reader:
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
mandatory_columns = [
|
|
189
|
+
v for k, v in self.index_mapping.items() if not k.startswith("?")
|
|
190
190
|
]
|
|
191
|
+
missing_columns = [x for x in mandatory_columns if x not in row.keys()]
|
|
191
192
|
if missing_columns:
|
|
192
193
|
raise ColumnNotFoundException(f"{', '.join(missing_columns)}")
|
|
193
194
|
lang = self.__determine_language(row)
|
|
194
195
|
previous_id = None
|
|
195
196
|
for type, identifying_column in self.index_mapping.items():
|
|
197
|
+
is_type_optional = False
|
|
198
|
+
if type.startswith("?"):
|
|
199
|
+
is_type_optional = True
|
|
200
|
+
type = type.lstrip("?")
|
|
201
|
+
if not row.get(identifying_column) and is_type_optional:
|
|
202
|
+
continue
|
|
196
203
|
id = row[identifying_column]
|
|
197
204
|
if type not in indexed_dict:
|
|
198
205
|
indexed_dict[type] = dict()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from copy import deepcopy
|
|
3
3
|
from elody.migration.base_object_migrator import BaseObjectMigrator
|
|
4
|
+
from policy_factory import get_user_context # pyright: ignore
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class BaseObjectConfiguration(ABC):
|
|
@@ -10,20 +11,24 @@ class BaseObjectConfiguration(ABC):
|
|
|
10
11
|
@abstractmethod
|
|
11
12
|
def crud(self):
|
|
12
13
|
return {
|
|
13
|
-
"collection": "entities",
|
|
14
|
-
"collection_history": "history",
|
|
15
14
|
"creator": lambda post_body, **kwargs: post_body,
|
|
15
|
+
"document_content_patcher": lambda *, document, content, overwrite=False, **kwargs: self._document_content_patcher(
|
|
16
|
+
document=document,
|
|
17
|
+
content=content,
|
|
18
|
+
overwrite=overwrite,
|
|
19
|
+
**kwargs,
|
|
20
|
+
),
|
|
16
21
|
"nested_matcher_builder": lambda object_lists, keys_info, value: self.__build_nested_matcher(
|
|
17
22
|
object_lists, keys_info, value
|
|
18
23
|
),
|
|
19
24
|
"post_crud_hook": lambda **kwargs: None,
|
|
20
|
-
"pre_crud_hook": lambda **kwargs:
|
|
25
|
+
"pre_crud_hook": lambda *, document, **kwargs: document,
|
|
21
26
|
"storage_type": "db",
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
@abstractmethod
|
|
25
30
|
def document_info(self):
|
|
26
|
-
return {
|
|
31
|
+
return {}
|
|
27
32
|
|
|
28
33
|
@abstractmethod
|
|
29
34
|
def logging(self, flat_document, **kwargs):
|
|
@@ -33,7 +38,7 @@ class BaseObjectConfiguration(ABC):
|
|
|
33
38
|
"schema": f"{flat_document.get('schema.type')}:{flat_document.get('schema.version')}",
|
|
34
39
|
}
|
|
35
40
|
try:
|
|
36
|
-
user_context =
|
|
41
|
+
user_context = get_user_context()
|
|
37
42
|
info_labels["http_method"] = user_context.bag.get("http_method")
|
|
38
43
|
info_labels["requested_endpoint"] = user_context.bag.get(
|
|
39
44
|
"requested_endpoint"
|
|
@@ -65,20 +70,46 @@ class BaseObjectConfiguration(ABC):
|
|
|
65
70
|
|
|
66
71
|
return "function", validator
|
|
67
72
|
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
key,
|
|
73
|
+
def _document_content_patcher(
|
|
74
|
+
self, *, document, content, overwrite=False, **kwargs
|
|
75
|
+
):
|
|
76
|
+
raise NotImplementedError(
|
|
77
|
+
"Provide concrete implementation in child object configuration"
|
|
74
78
|
)
|
|
75
|
-
return post_body
|
|
76
79
|
|
|
77
|
-
def
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
def _merge_object_lists(self, source, target, object_list_key):
|
|
81
|
+
for target_item in target:
|
|
82
|
+
for source_item in source:
|
|
83
|
+
if source_item[object_list_key] == target_item[object_list_key]:
|
|
84
|
+
source.remove(source_item)
|
|
85
|
+
return [*source, *target]
|
|
86
|
+
|
|
87
|
+
def _get_user_context_id(self):
|
|
88
|
+
try:
|
|
89
|
+
return get_user_context().id
|
|
90
|
+
except Exception:
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
def _sanitize_document(self, *, document, **kwargs):
|
|
94
|
+
sanitized_document = {}
|
|
95
|
+
document_deepcopy = deepcopy(document)
|
|
96
|
+
for key, value in document_deepcopy.items():
|
|
97
|
+
if isinstance(value, dict):
|
|
98
|
+
sanitized_value = BaseObjectConfiguration._sanitize_document(
|
|
99
|
+
self, document=value
|
|
100
|
+
)
|
|
101
|
+
if sanitized_value:
|
|
102
|
+
sanitized_document[key] = sanitized_value
|
|
103
|
+
elif value:
|
|
104
|
+
sanitized_document[key] = value
|
|
105
|
+
return sanitized_document
|
|
106
|
+
|
|
107
|
+
def _should_create_history_object(self):
|
|
108
|
+
try:
|
|
109
|
+
get_user_context()
|
|
110
|
+
return bool(self.crud().get("collection_history"))
|
|
111
|
+
except Exception:
|
|
112
|
+
return False
|
|
82
113
|
|
|
83
114
|
def _sort_document_keys(self, document):
|
|
84
115
|
def sort_keys(data):
|
|
@@ -98,12 +129,13 @@ class BaseObjectConfiguration(ABC):
|
|
|
98
129
|
else:
|
|
99
130
|
return data
|
|
100
131
|
|
|
101
|
-
for key, value in self.document_info()
|
|
132
|
+
for key, value in self.document_info().get("object_lists", {}).items():
|
|
102
133
|
if document.get(key):
|
|
103
134
|
document[key] = sorted(
|
|
104
135
|
document[key], key=lambda property: property[value]
|
|
105
136
|
)
|
|
106
137
|
sort_keys(document)
|
|
138
|
+
return document
|
|
107
139
|
|
|
108
140
|
def __build_nested_matcher(self, object_lists, keys_info, value, index=0):
|
|
109
141
|
if index == 0 and not any(info["object_list"] for info in keys_info):
|
|
@@ -135,10 +167,3 @@ class BaseObjectConfiguration(ABC):
|
|
|
135
167
|
return elem_match if index > 0 else {info["key"]: {"$all": [elem_match]}}
|
|
136
168
|
|
|
137
169
|
raise Exception(f"Unable to build nested matcher. See keys_info: {keys_info}")
|
|
138
|
-
|
|
139
|
-
def __merge_object_lists(self, source, target, key):
|
|
140
|
-
for target_item in target:
|
|
141
|
-
for source_item in source:
|
|
142
|
-
if source_item[key] == target_item[key]:
|
|
143
|
-
source.remove(source_item)
|
|
144
|
-
return [*source, *target]
|
|
@@ -12,6 +12,8 @@ class ElodyConfiguration(BaseObjectConfiguration):
|
|
|
12
12
|
|
|
13
13
|
def crud(self):
|
|
14
14
|
crud = {
|
|
15
|
+
"collection": "entities",
|
|
16
|
+
"collection_history": "history",
|
|
15
17
|
"creator": lambda post_body, **kwargs: self._creator(post_body, **kwargs),
|
|
16
18
|
"post_crud_hook": lambda **kwargs: self._post_crud_hook(**kwargs),
|
|
17
19
|
"pre_crud_hook": lambda **kwargs: self._pre_crud_hook(**kwargs),
|
|
@@ -37,7 +39,6 @@ class ElodyConfiguration(BaseObjectConfiguration):
|
|
|
37
39
|
self,
|
|
38
40
|
post_body,
|
|
39
41
|
*,
|
|
40
|
-
get_user_context,
|
|
41
42
|
flat_post_body={},
|
|
42
43
|
document_defaults={},
|
|
43
44
|
):
|
|
@@ -65,36 +66,79 @@ class ElodyConfiguration(BaseObjectConfiguration):
|
|
|
65
66
|
"relations": [],
|
|
66
67
|
"schema": {"type": self.SCHEMA_TYPE, "version": self.SCHEMA_VERSION},
|
|
67
68
|
}
|
|
68
|
-
if
|
|
69
|
-
template["computed_values"]["created_by"] =
|
|
70
|
-
|
|
71
|
-
for key in self.document_info()["object_lists"].
|
|
72
|
-
|
|
69
|
+
if user_context_id := self._get_user_context_id():
|
|
70
|
+
template["computed_values"]["created_by"] = user_context_id
|
|
71
|
+
|
|
72
|
+
for key, object_list_key in self.document_info()["object_lists"].items():
|
|
73
|
+
if not key.startswith("lookup.virtual_relations"):
|
|
74
|
+
post_body[key] = self._merge_object_lists(
|
|
75
|
+
document_defaults.get(key, []),
|
|
76
|
+
post_body.get(key, []),
|
|
77
|
+
object_list_key,
|
|
78
|
+
)
|
|
73
79
|
document = {**template, **document_defaults, **post_body}
|
|
74
80
|
|
|
75
|
-
self._sanitize_document(
|
|
76
|
-
|
|
81
|
+
document = self._sanitize_document(
|
|
82
|
+
document=document,
|
|
83
|
+
object_list_name="metadata",
|
|
84
|
+
object_list_value_field_name="value",
|
|
85
|
+
)
|
|
86
|
+
document = self._sort_document_keys(document)
|
|
87
|
+
return document
|
|
88
|
+
|
|
89
|
+
def _document_content_patcher(
|
|
90
|
+
self, *, document, content, overwrite=False, **kwargs
|
|
91
|
+
):
|
|
92
|
+
object_lists = self.document_info().get("object_lists", {})
|
|
93
|
+
if overwrite:
|
|
94
|
+
document = content
|
|
95
|
+
else:
|
|
96
|
+
for key, value in content.items():
|
|
97
|
+
if key in object_lists:
|
|
98
|
+
if key != "relations":
|
|
99
|
+
for value_element in value:
|
|
100
|
+
for item_element in document[key]:
|
|
101
|
+
if (
|
|
102
|
+
item_element[object_lists[key]]
|
|
103
|
+
== value_element[object_lists[key]]
|
|
104
|
+
):
|
|
105
|
+
document[key].remove(item_element)
|
|
106
|
+
break
|
|
107
|
+
document[key].extend(value)
|
|
108
|
+
else:
|
|
109
|
+
document[key] = value
|
|
110
|
+
|
|
77
111
|
return document
|
|
78
112
|
|
|
79
|
-
def _post_crud_hook(self, **
|
|
113
|
+
def _post_crud_hook(self, **kwargs):
|
|
80
114
|
pass
|
|
81
115
|
|
|
82
|
-
def _pre_crud_hook(self, *, crud, document={},
|
|
116
|
+
def _pre_crud_hook(self, *, crud, document={}, **kwargs):
|
|
83
117
|
if document:
|
|
84
|
-
self._sanitize_document(
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
document = self._sanitize_document(
|
|
119
|
+
document=document,
|
|
120
|
+
object_list_name="metadata",
|
|
121
|
+
object_list_value_field_name="value",
|
|
87
122
|
)
|
|
88
|
-
self.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
try:
|
|
92
|
-
return get_user_context().email
|
|
93
|
-
except Exception:
|
|
94
|
-
return None
|
|
123
|
+
document = self.__patch_document_computed_values(crud, document)
|
|
124
|
+
document = self._sort_document_keys(document)
|
|
125
|
+
return document
|
|
95
126
|
|
|
96
|
-
def
|
|
127
|
+
def _sanitize_document(
|
|
128
|
+
self, *, document, object_list_name, object_list_value_field_name, **kwargs
|
|
129
|
+
):
|
|
130
|
+
sanitized_document = super()._sanitize_document(document=document)
|
|
131
|
+
object_list = document[object_list_name]
|
|
132
|
+
for element in object_list:
|
|
133
|
+
if not element[object_list_value_field_name]:
|
|
134
|
+
sanitized_document[object_list_name].remove(element)
|
|
135
|
+
return sanitized_document
|
|
136
|
+
|
|
137
|
+
def __patch_document_computed_values(self, crud, document):
|
|
138
|
+
if not document.get("computed_values"):
|
|
139
|
+
document["computed_values"] = {}
|
|
97
140
|
document["computed_values"].update({"event": crud})
|
|
98
141
|
document["computed_values"].update({"modified_at": datetime.now(timezone.utc)})
|
|
99
|
-
if email := self.
|
|
142
|
+
if email := self._get_user_context_id():
|
|
100
143
|
document["computed_values"].update({"modified_by": email})
|
|
144
|
+
return document
|
|
@@ -16,8 +16,8 @@ class JobConfiguration(ElodyConfiguration):
|
|
|
16
16
|
def document_info(self):
|
|
17
17
|
return super().document_info()
|
|
18
18
|
|
|
19
|
-
def logging(self,
|
|
20
|
-
return super().logging(
|
|
19
|
+
def logging(self, flat_document, **kwargs):
|
|
20
|
+
return super().logging(flat_document, **kwargs)
|
|
21
21
|
|
|
22
22
|
def migration(self):
|
|
23
23
|
return super().migration()
|
|
@@ -21,9 +21,10 @@ def set_permissions(permissions: dict, placeholders: list[str] = []):
|
|
|
21
21
|
def get_permissions(role: str, user_context: UserContext):
|
|
22
22
|
permissions = deepcopy(_permissions)
|
|
23
23
|
|
|
24
|
-
for
|
|
24
|
+
for placeholder_key in _placeholders:
|
|
25
|
+
placeholder_value = user_context.bag.get(placeholder_key.lower())
|
|
25
26
|
permissions = __replace_permission_placeholders(
|
|
26
|
-
permissions,
|
|
27
|
+
permissions, placeholder_key, placeholder_value
|
|
27
28
|
)
|
|
28
29
|
return permissions.get(role, {}) # pyright: ignore
|
|
29
30
|
|
|
@@ -84,8 +85,8 @@ def handle_single_item_request(
|
|
|
84
85
|
|
|
85
86
|
def mask_protected_content_post_request_hook(user_context: UserContext, permissions):
|
|
86
87
|
def __post_request_hook(response):
|
|
87
|
-
items =
|
|
88
|
-
for item in
|
|
88
|
+
items = []
|
|
89
|
+
for item in response["results"]:
|
|
89
90
|
try:
|
|
90
91
|
(
|
|
91
92
|
item_in_storage_format,
|
|
@@ -104,6 +105,7 @@ def mask_protected_content_post_request_hook(user_context: UserContext, permissi
|
|
|
104
105
|
"read",
|
|
105
106
|
object_lists,
|
|
106
107
|
)
|
|
108
|
+
items.append(user_context.bag["requested_item"])
|
|
107
109
|
except Exception as exception:
|
|
108
110
|
log.debug(
|
|
109
111
|
f"{exception.__class__.__name__}: {str(exception)}",
|
|
@@ -111,6 +113,7 @@ def mask_protected_content_post_request_hook(user_context: UserContext, permissi
|
|
|
111
113
|
)
|
|
112
114
|
raise exception
|
|
113
115
|
|
|
116
|
+
response["results"] = items
|
|
114
117
|
return response
|
|
115
118
|
|
|
116
119
|
return __post_request_hook
|
|
@@ -122,7 +125,7 @@ def __prepare_item_for_permission_check(item, permissions, crud):
|
|
|
122
125
|
return item, None, None, None
|
|
123
126
|
|
|
124
127
|
config = get_object_configuration_mapper().get(item["type"])
|
|
125
|
-
object_lists = config.document_info()
|
|
128
|
+
object_lists = config.document_info().get("object_lists", {})
|
|
126
129
|
flat_item = flatten_dict(object_lists, item)
|
|
127
130
|
|
|
128
131
|
return (
|
|
@@ -188,16 +191,23 @@ def __is_allowed_to_crud_item_keys(
|
|
|
188
191
|
if condition_match:
|
|
189
192
|
if crud == "read":
|
|
190
193
|
keys_info = interpret_flat_key(restricted_key, object_lists)
|
|
191
|
-
element = item_in_storage_format
|
|
192
194
|
for info in keys_info:
|
|
193
195
|
if info["object_list"]:
|
|
194
196
|
element = __get_element_from_object_list_of_item(
|
|
195
|
-
|
|
197
|
+
item_in_storage_format,
|
|
196
198
|
info["key"],
|
|
197
199
|
info["object_key"],
|
|
198
200
|
object_lists,
|
|
199
201
|
)
|
|
200
|
-
|
|
202
|
+
item_in_storage_format[info["key"]].remove(element)
|
|
203
|
+
break
|
|
204
|
+
else:
|
|
205
|
+
try:
|
|
206
|
+
del item_in_storage_format[keys_info[0]["key"]][
|
|
207
|
+
keys_info[1]["key"]
|
|
208
|
+
]
|
|
209
|
+
except KeyError:
|
|
210
|
+
pass
|
|
201
211
|
else:
|
|
202
212
|
if flat_request_body.get(restricted_key):
|
|
203
213
|
user_context.bag["restricted_keys"].append(restricted_key)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: elody
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.157
|
|
4
4
|
Summary: elody SDK for Python
|
|
5
5
|
Author-email: Inuits <developers@inuits.eu>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -362,7 +362,7 @@ Requires-Dist: urllib3>=1.26.16
|
|
|
362
362
|
Provides-Extra: loader
|
|
363
363
|
Requires-Dist: APScheduler>=3.10.4; extra == "loader"
|
|
364
364
|
Requires-Dist: cloudevents>=1.9.0; extra == "loader"
|
|
365
|
-
Requires-Dist: inuits-policy-based-auth>=
|
|
365
|
+
Requires-Dist: inuits-policy-based-auth>=10.0.1; extra == "loader"
|
|
366
366
|
Requires-Dist: pytz>=2024.1; extra == "loader"
|
|
367
367
|
Requires-Dist: six>=1.16.0; extra == "loader"
|
|
368
368
|
Requires-Dist: tzlocal>=5.2; extra == "loader"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
elody/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
|
|
3
3
|
elody/client.py,sha256=Es0iloHq9aOiMgXfwssEiV1Nqvvd6Z3RfsyoJvIZ48I,8280
|
|
4
|
-
elody/csv.py,sha256=
|
|
4
|
+
elody/csv.py,sha256=Ui9p3N-N9jQFvWTVecuUqqTfiN1HdpGmFGEqQK2g7OY,13215
|
|
5
5
|
elody/error_codes.py,sha256=OBHvsKLRN5XU1Ro8Y5dwXWPE8zsiTBPwdoMPs-nL2Z4,3906
|
|
6
6
|
elody/exceptions.py,sha256=5KSw2sPCZz3lDIJX4LiR2iL9n4m4KIil04D1d3X5rd0,968
|
|
7
7
|
elody/job.py,sha256=QnN6Q45yqRimziqJX9SHrTVFVvky5mAc1WEza9ia8_w,2811
|
|
@@ -12,12 +12,12 @@ elody/validator.py,sha256=G7Ya538EJHCFzOxEri2OcFMabfLBCtTKxuf4os_KuNw,260
|
|
|
12
12
|
elody/migration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
elody/migration/base_object_migrator.py,sha256=n8uvgGfjEUy60G47RD7Y-oxp1vHLOauwPMDl87LcxtU,436
|
|
14
14
|
elody/object_configurations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
elody/object_configurations/base_object_configuration.py,sha256=
|
|
16
|
-
elody/object_configurations/elody_configuration.py,sha256=
|
|
17
|
-
elody/object_configurations/job_configuration.py,sha256=
|
|
15
|
+
elody/object_configurations/base_object_configuration.py,sha256=2yL8cCgWyT9lwTrpwjL_6TOYynWXRj6XdaHcCGC4RPM,6373
|
|
16
|
+
elody/object_configurations/elody_configuration.py,sha256=Bp3OSHBHuyPs-ubIULzl9wqZd3akYD2idh3mhYo7zu0,5339
|
|
17
|
+
elody/object_configurations/job_configuration.py,sha256=FagGQ7WBAcRHTeftezGOa7ykuYQvMB2GKeri80GkcMw,1813
|
|
18
18
|
elody/policies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
elody/policies/helpers.py,sha256=AV3wtvthJafW6ueEYGxggB5kk5knWTWzh3zq29Y1-ws,1434
|
|
20
|
-
elody/policies/permission_handler.py,sha256=
|
|
20
|
+
elody/policies/permission_handler.py,sha256=1aXA_xfRxdTfHZY5xRwQqJp5pjSzBrhko4eGRT38WLQ,9505
|
|
21
21
|
elody/policies/tenant_id_resolver.py,sha256=BIl6lr9AH6Q_aZSsxF24B7ramkIZH-R-8bpLrTvYLtM,13796
|
|
22
22
|
elody/policies/authentication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
elody/policies/authentication/base_user_tenant_validation_policy.py,sha256=fxvrB4iG6fehBh6b4XS8AWewtNsCABgSooma5ljjZk4,5144
|
|
@@ -36,10 +36,10 @@ elody/policies/authorization/tenant_request_policy.py,sha256=dEgblwRAqwWVcE-O7Jn
|
|
|
36
36
|
tests/__init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
37
|
tests/data.py,sha256=Q3oxduf-E3m-Z5G_p3fcs8jVy6g10I7zXKL1m94UVMI,2906
|
|
38
38
|
tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
-
tests/unit/test_csv.py,sha256=
|
|
40
|
-
tests/unit/test_utils.py,sha256=
|
|
41
|
-
elody-0.0.
|
|
42
|
-
elody-0.0.
|
|
43
|
-
elody-0.0.
|
|
44
|
-
elody-0.0.
|
|
45
|
-
elody-0.0.
|
|
39
|
+
tests/unit/test_csv.py,sha256=NQaOhehfQ4GuXku0Y1SA8DYjJeqqidbF50zEHAi8RZA,15923
|
|
40
|
+
tests/unit/test_utils.py,sha256=g63szcEZyHhCOtrW4BnNbcgVca3oYPIOLjBdIzNwwN0,8784
|
|
41
|
+
elody-0.0.157.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
|
|
42
|
+
elody-0.0.157.dist-info/METADATA,sha256=ZI5G47P1QM9FsrLjWu7b16W7htJ4B7wxFUptsUHNAy4,23283
|
|
43
|
+
elody-0.0.157.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
44
|
+
elody-0.0.157.dist-info/top_level.txt,sha256=E0mImupLj0KmtUUCXRYEoLDRaSkuiGaOIIseAa0oQ-M,21
|
|
45
|
+
elody-0.0.157.dist-info/RECORD,,
|
tests/unit/test_csv.py
CHANGED
|
@@ -35,6 +35,14 @@ sample_multiple_keywords_csv_vliz = """same_entity,title,description,coordinates
|
|
|
35
35
|
1,,,,keyword2,,,,,,,,,,,leeuw.jpg,,,,,,,keyword_mediafile,,,,
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
|
+
sample_csv_without_mediafile_digi = """external_id,external_system,type,asset_copyright_color
|
|
39
|
+
tg:lhps:32930:m1,arches,asset,green
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
sample_csv_without_mediafile_vliz = """same_entity,title,description,coordinates,media_keyword,language,asset_category,location_type,marine_region,event,project,partner,creator_person,owner_partner,type
|
|
43
|
+
1,This is a media entity without a mediafile,This is a description,,keyword1,,,,,,,,person1,partner1,media
|
|
44
|
+
"""
|
|
45
|
+
|
|
38
46
|
expected_basic_objects_digipolis = {
|
|
39
47
|
"entities": [
|
|
40
48
|
{
|
|
@@ -181,13 +189,47 @@ expected_multiple_keywords_objects_vliz = {
|
|
|
181
189
|
],
|
|
182
190
|
}
|
|
183
191
|
|
|
192
|
+
expected_only_entities_object_digipolis = {
|
|
193
|
+
"entities": [
|
|
194
|
+
{
|
|
195
|
+
"matching_id": "tg:lhps:32930:m1",
|
|
196
|
+
"metadata": [
|
|
197
|
+
{"key": "external_id", "value": "tg:lhps:32930:m1", "lang": "en"},
|
|
198
|
+
{"key": "external_system", "value": "arches", "lang": "en"},
|
|
199
|
+
{"key": "copyright_color", "value": "green", "lang": "en"},
|
|
200
|
+
],
|
|
201
|
+
"type": "asset",
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
expected_only_entities_object_vliz = {
|
|
207
|
+
"entities": [
|
|
208
|
+
{
|
|
209
|
+
"matching_id": "1",
|
|
210
|
+
"metadata": [
|
|
211
|
+
{
|
|
212
|
+
"key": "title",
|
|
213
|
+
"value": "This is a media entity without a mediafile",
|
|
214
|
+
"lang": "",
|
|
215
|
+
},
|
|
216
|
+
{"key": "description", "value": "This is a description", "lang": ""},
|
|
217
|
+
{"key": "media_keyword", "value": "keyword1", "lang": ""},
|
|
218
|
+
{"key": "creator_person", "value": "person1", "lang": ""},
|
|
219
|
+
{"key": "owner_partner", "value": "partner1", "lang": ""},
|
|
220
|
+
],
|
|
221
|
+
"type": "media",
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
|
|
184
226
|
|
|
185
227
|
def init_digipolis_csv_object(csv):
|
|
186
228
|
csv_multi_object = CSVMultiObject(
|
|
187
229
|
csv,
|
|
188
230
|
index_mapping={
|
|
189
231
|
"entities": "external_id",
|
|
190
|
-
"mediafiles": "file_identifier",
|
|
232
|
+
"?mediafiles": "file_identifier",
|
|
191
233
|
},
|
|
192
234
|
object_field_mapping={
|
|
193
235
|
"mediafiles": [
|
|
@@ -246,7 +288,7 @@ def init_digipolis_csv_object(csv):
|
|
|
246
288
|
def init_vliz_csv_object(csv):
|
|
247
289
|
csv_multi_object = CSVMultiObject(
|
|
248
290
|
csv,
|
|
249
|
-
index_mapping={"entities": "same_entity", "mediafiles": "filename"},
|
|
291
|
+
index_mapping={"entities": "same_entity", "?mediafiles": "filename"},
|
|
250
292
|
object_field_mapping={
|
|
251
293
|
"mediafiles": [
|
|
252
294
|
"filename",
|
|
@@ -342,15 +384,27 @@ def test_meemoo_csv_digipolis():
|
|
|
342
384
|
assert csv_multi_object.objects == expected_meemoo_objects_digipolis
|
|
343
385
|
|
|
344
386
|
|
|
387
|
+
def test_csv_with_only_an_entity_digipolis():
|
|
388
|
+
csv_multi_object = init_digipolis_csv_object(sample_csv_without_mediafile_digi)
|
|
389
|
+
assert csv_multi_object.objects == expected_only_entities_object_digipolis
|
|
390
|
+
|
|
391
|
+
|
|
345
392
|
# Tests CSVMultiObject VLIZ
|
|
346
393
|
def test_basic_csv_vliz():
|
|
347
394
|
csv_multi_object = init_vliz_csv_object(sample_basic_csv_vliz)
|
|
348
395
|
assert csv_multi_object.objects == expected_basic_objects_vliz
|
|
349
|
-
|
|
396
|
+
|
|
397
|
+
|
|
350
398
|
def test_basic_csv_digipolis_with_wrong_values():
|
|
351
399
|
with pytest.raises(ColumnNotFoundException):
|
|
352
400
|
init_vliz_csv_object(sample_basic_csv_vliz_missing_values)
|
|
353
|
-
|
|
401
|
+
|
|
402
|
+
|
|
354
403
|
def test_multiple_keywords_csv_vliz():
|
|
355
404
|
csv_multi_object = init_vliz_csv_object(sample_multiple_keywords_csv_vliz)
|
|
356
405
|
assert csv_multi_object.objects == expected_multiple_keywords_objects_vliz
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def test_csv_with_only_an_entity_vliz():
|
|
409
|
+
csv_multi_object = init_vliz_csv_object(sample_csv_without_mediafile_vliz)
|
|
410
|
+
assert csv_multi_object.objects == expected_only_entities_object_vliz
|
tests/unit/test_utils.py
CHANGED
|
@@ -11,7 +11,7 @@ from elody.util import (
|
|
|
11
11
|
mediafile_is_public,
|
|
12
12
|
read_json_as_dict,
|
|
13
13
|
parse_url_unfriendly_string,
|
|
14
|
-
CustomJSONEncoder
|
|
14
|
+
CustomJSONEncoder,
|
|
15
15
|
)
|
|
16
16
|
from data import mediafile1, mediafile2
|
|
17
17
|
from datetime import datetime, timezone
|
|
@@ -24,12 +24,14 @@ def test_default_method_with_datetime():
|
|
|
24
24
|
result = encoder.default(dt)
|
|
25
25
|
assert result == "2023-10-01T12:00:00+00:00"
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
def test_default_method_with_naive_datetime():
|
|
28
29
|
encoder = CustomJSONEncoder()
|
|
29
30
|
dt = datetime(2023, 10, 1, 12, 0, 0)
|
|
30
31
|
result = encoder.default(dt)
|
|
31
32
|
assert result == "2023-10-01T10:00:00+00:00"
|
|
32
33
|
|
|
34
|
+
|
|
33
35
|
def test_encode_method_with_non_datetime():
|
|
34
36
|
encoder = CustomJSONEncoder()
|
|
35
37
|
obj = {"key": "value"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|