eegdash 0.0.1__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 eegdash might be problematic. Click here for more details.
- eegdash/SignalStore/__init__.py +0 -0
- eegdash/SignalStore/signalstore/__init__.py +3 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/abstract_read_adapter.py +13 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/domain_modeling/schema_read_adapter.py +16 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/domain_modeling/vocabulary_read_adapter.py +19 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/handmade_records/excel_study_organizer_read_adapter.py +114 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/axona/axona_read_adapter.py +912 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/ReadIntanSpikeFile.py +140 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/intan_read_adapter.py +29 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/intanutil/__init__.py +0 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/intanutil/data_to_result.py +62 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/intanutil/get_bytes_per_data_block.py +36 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/intanutil/notch_filter.py +50 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/intanutil/qstring.py +41 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/intanutil/read_header.py +135 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/intanutil/read_one_data_block.py +45 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhd_format/load_intan_rhd_format.py +204 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/intanutil/__init__.py +0 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/intanutil/data_to_result.py +60 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/intanutil/get_bytes_per_data_block.py +37 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/intanutil/notch_filter.py +50 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/intanutil/qstring.py +41 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/intanutil/read_header.py +153 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/intanutil/read_one_data_block.py +47 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/intan/load_intan_rhs_format/load_intan_rhs_format.py +213 -0
- eegdash/SignalStore/signalstore/adapters/read_adapters/recording_acquisitions/neurodata_without_borders/neurodata_without_borders_read_adapter.py +14 -0
- eegdash/SignalStore/signalstore/operations/__init__.py +4 -0
- eegdash/SignalStore/signalstore/operations/handler_executor.py +22 -0
- eegdash/SignalStore/signalstore/operations/handler_factory.py +41 -0
- eegdash/SignalStore/signalstore/operations/handlers/base_handler.py +44 -0
- eegdash/SignalStore/signalstore/operations/handlers/domain/property_model_handlers.py +79 -0
- eegdash/SignalStore/signalstore/operations/handlers/domain/schema_handlers.py +3 -0
- eegdash/SignalStore/signalstore/operations/helpers/abstract_helper.py +17 -0
- eegdash/SignalStore/signalstore/operations/helpers/neuroscikit_extractor.py +33 -0
- eegdash/SignalStore/signalstore/operations/helpers/neuroscikit_rawio.py +165 -0
- eegdash/SignalStore/signalstore/operations/helpers/spikeinterface_helper.py +100 -0
- eegdash/SignalStore/signalstore/operations/helpers/wrappers/neo_wrappers.py +21 -0
- eegdash/SignalStore/signalstore/operations/helpers/wrappers/nwb_wrappers.py +27 -0
- eegdash/SignalStore/signalstore/store/__init__.py +8 -0
- eegdash/SignalStore/signalstore/store/data_access_objects.py +1181 -0
- eegdash/SignalStore/signalstore/store/datafile_adapters.py +131 -0
- eegdash/SignalStore/signalstore/store/repositories.py +928 -0
- eegdash/SignalStore/signalstore/store/store_errors.py +68 -0
- eegdash/SignalStore/signalstore/store/unit_of_work.py +97 -0
- eegdash/SignalStore/signalstore/store/unit_of_work_provider.py +67 -0
- eegdash/SignalStore/signalstore/utilities/data_adapters/spike_interface_adapters/si_recording.py +1 -0
- eegdash/SignalStore/signalstore/utilities/data_adapters/spike_interface_adapters/si_sorter.py +1 -0
- eegdash/SignalStore/signalstore/utilities/testing/data_mocks.py +513 -0
- eegdash/SignalStore/signalstore/utilities/tools/dataarrays.py +49 -0
- eegdash/SignalStore/signalstore/utilities/tools/mongo_records.py +25 -0
- eegdash/SignalStore/signalstore/utilities/tools/operation_response.py +78 -0
- eegdash/SignalStore/signalstore/utilities/tools/purge_orchestration_response.py +21 -0
- eegdash/SignalStore/signalstore/utilities/tools/quantities.py +15 -0
- eegdash/SignalStore/signalstore/utilities/tools/strings.py +38 -0
- eegdash/SignalStore/signalstore/utilities/tools/time.py +17 -0
- eegdash/SignalStore/tests/conftest.py +799 -0
- eegdash/SignalStore/tests/data/valid_data/data_arrays/make_fake_data.py +59 -0
- eegdash/SignalStore/tests/unit/store/conftest.py +0 -0
- eegdash/SignalStore/tests/unit/store/test_data_access_objects.py +1235 -0
- eegdash/SignalStore/tests/unit/store/test_repositories.py +1309 -0
- eegdash/SignalStore/tests/unit/store/test_unit_of_work.py +7 -0
- eegdash/SignalStore/tests/unit/test_ci_cd.py +8 -0
- eegdash/__init__.py +1 -0
- eegdash/aws_ingest.py +29 -0
- eegdash/data_utils.py +213 -0
- eegdash/main.py +17 -0
- eegdash/signalstore_data_utils.py +280 -0
- eegdash-0.0.1.dist-info/LICENSE +20 -0
- eegdash-0.0.1.dist-info/METADATA +72 -0
- eegdash-0.0.1.dist-info/RECORD +72 -0
- eegdash-0.0.1.dist-info/WHEEL +5 -0
- eegdash-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import yaml
|
|
3
|
+
import json
|
|
4
|
+
import upath
|
|
5
|
+
import mongomock
|
|
6
|
+
import xarray as xr
|
|
7
|
+
import numpy as np
|
|
8
|
+
import fsspec
|
|
9
|
+
from fsspec.implementations.local import LocalFileSystem
|
|
10
|
+
from fsspec.implementations.dirfs import DirFileSystem
|
|
11
|
+
from upath import UPath
|
|
12
|
+
from time import sleep
|
|
13
|
+
|
|
14
|
+
from signalstore.store.data_access_objects import (
|
|
15
|
+
MongoDAO,
|
|
16
|
+
FileSystemDAO,
|
|
17
|
+
InMemoryObjectDAO,
|
|
18
|
+
datetime_to_microseconds,
|
|
19
|
+
microseconds_to_datetime,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from signalstore.store.repositories import (
|
|
23
|
+
DomainModelRepository, domain_model_json_schema,
|
|
24
|
+
DataRepository,
|
|
25
|
+
InMemoryObjectRepository,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from signalstore.store.datafile_adapters import (
|
|
29
|
+
XarrayDataArrayNetCDFAdapter,
|
|
30
|
+
XarrayDataArrayZarrAdapter,
|
|
31
|
+
AbstractDataFileAdapter,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
from signalstore.store import UnitOfWorkProvider
|
|
35
|
+
|
|
36
|
+
from signalstore.operations.helpers.abstract_helper import AbstractMutableHelper
|
|
37
|
+
|
|
38
|
+
from datetime import datetime, timezone, timedelta
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ==========================================================
|
|
42
|
+
# ==========================================================
|
|
43
|
+
# Utility Fixtures
|
|
44
|
+
# ==========================================================
|
|
45
|
+
# ==========================================================
|
|
46
|
+
|
|
47
|
+
@pytest.fixture
|
|
48
|
+
def timestamp():
|
|
49
|
+
ts = datetime.now()
|
|
50
|
+
# convert to UTC
|
|
51
|
+
ts = ts.astimezone(timezone.utc)
|
|
52
|
+
return ts
|
|
53
|
+
|
|
54
|
+
@pytest.fixture
|
|
55
|
+
def project():
|
|
56
|
+
return "testproject"
|
|
57
|
+
|
|
58
|
+
# ==========================================================
|
|
59
|
+
# ==========================================================
|
|
60
|
+
# Client
|
|
61
|
+
# ==========================================================
|
|
62
|
+
# ==========================================================
|
|
63
|
+
|
|
64
|
+
@pytest.fixture
|
|
65
|
+
def empty_client():
|
|
66
|
+
return mongomock.MongoClient()
|
|
67
|
+
|
|
68
|
+
# ==========================================================
|
|
69
|
+
# ==========================================================
|
|
70
|
+
# Data Access Objects
|
|
71
|
+
# ==========================================================
|
|
72
|
+
# ==========================================================
|
|
73
|
+
|
|
74
|
+
test_data_path = upath.UPath(__file__).parent / "data" / "valid_data"
|
|
75
|
+
invalid_test_data_path = upath.UPath(__file__).parent / "data" / "invalid_data"
|
|
76
|
+
|
|
77
|
+
# ===================
|
|
78
|
+
# Model MongoDAO
|
|
79
|
+
# ===================
|
|
80
|
+
|
|
81
|
+
# Property Models
|
|
82
|
+
# -------------------
|
|
83
|
+
# Load the JSON file into a list of dictionaries
|
|
84
|
+
property_models_path = test_data_path / "models" / "property_models.json"
|
|
85
|
+
with open(property_models_path, 'r') as file:
|
|
86
|
+
raw_property_models = json.load(file)
|
|
87
|
+
|
|
88
|
+
# generate fixtures that provide individual property models
|
|
89
|
+
for property_model in raw_property_models:
|
|
90
|
+
schema_name = property_model["schema_name"]
|
|
91
|
+
namestring = f"{schema_name}_property_model"
|
|
92
|
+
@pytest.fixture(name=namestring)
|
|
93
|
+
def _property_model_fixture(timestamp, property_model=property_model):
|
|
94
|
+
property_model["time_of_save"] = timestamp
|
|
95
|
+
property_model["time_of_removal"] = None
|
|
96
|
+
return property_model
|
|
97
|
+
globals()[namestring] = _property_model_fixture
|
|
98
|
+
|
|
99
|
+
# generate a fixture that provides all the property models
|
|
100
|
+
@pytest.fixture(name="property_models")
|
|
101
|
+
def _property_models_fixture(timestamp):
|
|
102
|
+
property_models = []
|
|
103
|
+
for property_model in raw_property_models:
|
|
104
|
+
property_model = property_model.copy()
|
|
105
|
+
property_model["time_of_save"] = timestamp
|
|
106
|
+
property_model["time_of_removal"] = None
|
|
107
|
+
property_models.append(property_model)
|
|
108
|
+
return property_models
|
|
109
|
+
|
|
110
|
+
# Metamodels
|
|
111
|
+
# -------------------
|
|
112
|
+
# Load the JSON files from folder into a list of dictionaries
|
|
113
|
+
metamodels_dir = test_data_path / "models" / "metamodels"
|
|
114
|
+
metamodel_filepaths = list(metamodels_dir.glob("*.json"))
|
|
115
|
+
raw_metamodels = []
|
|
116
|
+
for filepath in metamodel_filepaths:
|
|
117
|
+
with open(filepath, 'r') as file:
|
|
118
|
+
raw_metamodels.append(json.load(file))
|
|
119
|
+
|
|
120
|
+
# generate fixtures that provide individual metamodels
|
|
121
|
+
for metamodel in raw_metamodels:
|
|
122
|
+
schema_name = metamodel["schema_name"]
|
|
123
|
+
namestring = f"{schema_name}_metamodel"
|
|
124
|
+
@pytest.fixture(name=namestring)
|
|
125
|
+
def _metamodel_fixture(timestamp, metamodel=metamodel):
|
|
126
|
+
metamodel["time_of_save"] = timestamp
|
|
127
|
+
metamodel["time_of_removal"] = None
|
|
128
|
+
return metamodel
|
|
129
|
+
globals()[namestring] = _metamodel_fixture
|
|
130
|
+
|
|
131
|
+
# generate a fixture that provides all the metamodels
|
|
132
|
+
@pytest.fixture(name="metamodels")
|
|
133
|
+
def _metamodels_fixture(timestamp):
|
|
134
|
+
metamodels = []
|
|
135
|
+
for metamodel in raw_metamodels:
|
|
136
|
+
metamodel = metamodel.copy()
|
|
137
|
+
metamodel["time_of_save"] = timestamp
|
|
138
|
+
metamodel["time_of_removal"] = None
|
|
139
|
+
metamodels.append(metamodel)
|
|
140
|
+
return metamodels
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Data Models
|
|
144
|
+
# -------------------
|
|
145
|
+
# Load the JSON files from folder into a list of dictionaries
|
|
146
|
+
data_models_dir = test_data_path / "models" / "data_models"
|
|
147
|
+
data_model_filepaths = list(data_models_dir.glob("*.json"))
|
|
148
|
+
raw_data_models = []
|
|
149
|
+
for filepath in data_model_filepaths:
|
|
150
|
+
with open(filepath, 'r') as file:
|
|
151
|
+
raw_data_models.append(json.load(file))
|
|
152
|
+
|
|
153
|
+
# generate fixtures that provide individual data models
|
|
154
|
+
for data_model in raw_data_models:
|
|
155
|
+
schema_name = data_model["schema_name"]
|
|
156
|
+
namestring = f"{schema_name}_data_model"
|
|
157
|
+
@pytest.fixture(name=namestring)
|
|
158
|
+
def _data_model_fixture(timestamp, data_model=data_model):
|
|
159
|
+
data_model["time_of_save"] = timestamp
|
|
160
|
+
data_model["time_of_removal"] = None
|
|
161
|
+
return data_model
|
|
162
|
+
globals()[namestring] = _data_model_fixture
|
|
163
|
+
|
|
164
|
+
# generate a fixture that provides all the data models
|
|
165
|
+
@pytest.fixture(name="data_models")
|
|
166
|
+
def _data_models_fixture(timestamp):
|
|
167
|
+
data_models = []
|
|
168
|
+
for data_model in raw_data_models:
|
|
169
|
+
data_model = data_model.copy()
|
|
170
|
+
data_model["time_of_save"] = timestamp
|
|
171
|
+
data_model["time_of_removal"] = None
|
|
172
|
+
data_models.append(data_model)
|
|
173
|
+
return data_models
|
|
174
|
+
|
|
175
|
+
# Invalid Property Models
|
|
176
|
+
# -------------------
|
|
177
|
+
# Load the JSON file into a list of dictionaries
|
|
178
|
+
invalid_property_models_path = invalid_test_data_path / "models" / "property_models.json"
|
|
179
|
+
with open(invalid_property_models_path, 'r') as file:
|
|
180
|
+
raw_invalid_property_models = json.load(file)
|
|
181
|
+
|
|
182
|
+
# generate fixtures that provide individual property models
|
|
183
|
+
for property_model in raw_invalid_property_models:
|
|
184
|
+
schema_name = property_model["schema_name"]
|
|
185
|
+
namestring = f"{schema_name}_property_model"
|
|
186
|
+
@pytest.fixture(name=namestring)
|
|
187
|
+
def _invalid_property_model_fixture(timestamp, property_model=property_model):
|
|
188
|
+
property_model["time_of_save"] = timestamp
|
|
189
|
+
property_model["time_of_removal"] = None
|
|
190
|
+
return property_model
|
|
191
|
+
globals()[namestring] = _invalid_property_model_fixture
|
|
192
|
+
|
|
193
|
+
@pytest.fixture(name="models")
|
|
194
|
+
def _models_fixture(timestamp, property_models, metamodels, data_models):
|
|
195
|
+
models = []
|
|
196
|
+
for property_model in property_models:
|
|
197
|
+
property_model = property_model.copy()
|
|
198
|
+
property_model["time_of_save"] = timestamp
|
|
199
|
+
property_model["time_of_removal"] = None
|
|
200
|
+
models.append(property_model)
|
|
201
|
+
for metamodel in metamodels:
|
|
202
|
+
metamodel = metamodel.copy()
|
|
203
|
+
metamodel["time_of_save"] = timestamp
|
|
204
|
+
metamodel["time_of_removal"] = None
|
|
205
|
+
models.append(metamodel)
|
|
206
|
+
for data_model in data_models:
|
|
207
|
+
data_model = data_model.copy()
|
|
208
|
+
data_model["time_of_save"] = timestamp
|
|
209
|
+
data_model["time_of_removal"] = None
|
|
210
|
+
models.append(data_model)
|
|
211
|
+
return models
|
|
212
|
+
|
|
213
|
+
# generate a fixture that provides all the property models
|
|
214
|
+
@pytest.fixture(name="invalid_property_models")
|
|
215
|
+
def _invalid_property_models_fixture(timestamp, unit_of_measure_property_model):
|
|
216
|
+
invalid_property_models = []
|
|
217
|
+
for property_model in raw_invalid_property_models:
|
|
218
|
+
property_model = property_model.copy()
|
|
219
|
+
property_model["time_of_save"] = timestamp
|
|
220
|
+
property_model["time_of_removal"] = None
|
|
221
|
+
invalid_property_models.append(property_model)
|
|
222
|
+
# add property models from the valid set that are just missing a required field
|
|
223
|
+
required_fields = ["schema_title", "schema_description", "schema_type", "json_schema"]
|
|
224
|
+
for field in required_fields:
|
|
225
|
+
invalid_property_model = unit_of_measure_property_model.copy()
|
|
226
|
+
invalid_property_model.pop(field)
|
|
227
|
+
invalid_property_model["time_of_save"] = timestamp
|
|
228
|
+
invalid_property_model["time_of_removal"] = None
|
|
229
|
+
# rename the schema_name to make it unique
|
|
230
|
+
invalid_property_model["schema_name"] = f"invalid_property_model_missing_{field}"
|
|
231
|
+
invalid_property_models.append(invalid_property_model)
|
|
232
|
+
return invalid_property_models
|
|
233
|
+
|
|
234
|
+
# Invalid Data Models
|
|
235
|
+
# -------------------
|
|
236
|
+
# Load the JSON files from folder into a list of dictionaries
|
|
237
|
+
invalid_data_models_dir = invalid_test_data_path / "models" / "data_models"
|
|
238
|
+
invalid_data_model_filepaths = list(invalid_data_models_dir.glob("*.json"))
|
|
239
|
+
raw_invalid_data_models = []
|
|
240
|
+
for filepath in invalid_data_model_filepaths:
|
|
241
|
+
with open(filepath, 'r') as file:
|
|
242
|
+
raw_invalid_data_models.append(json.load(file))
|
|
243
|
+
|
|
244
|
+
# generate fixtures that provide individual data models
|
|
245
|
+
for data_model in raw_invalid_data_models:
|
|
246
|
+
schema_name = data_model["schema_name"]
|
|
247
|
+
namestring = f"{schema_name}_data_model"
|
|
248
|
+
@pytest.fixture(name=namestring)
|
|
249
|
+
def _invalid_data_model_fixture(timestamp, data_model=data_model):
|
|
250
|
+
data_model["time_of_save"] = timestamp
|
|
251
|
+
data_model["time_of_removal"] = None
|
|
252
|
+
return data_model
|
|
253
|
+
globals()[namestring] = _invalid_data_model_fixture
|
|
254
|
+
|
|
255
|
+
# generate a fixture that provides all the data models
|
|
256
|
+
@pytest.fixture(name="invalid_data_models")
|
|
257
|
+
def _invalid_data_models_fixture(timestamp, session_data_model):
|
|
258
|
+
invalid_data_models = []
|
|
259
|
+
for data_model in raw_invalid_data_models:
|
|
260
|
+
data_model = data_model.copy()
|
|
261
|
+
data_model["time_of_save"] = timestamp
|
|
262
|
+
data_model["time_of_removal"] = None
|
|
263
|
+
invalid_data_models.append(data_model)
|
|
264
|
+
# add data models from the valid set that are just missing a required field
|
|
265
|
+
required_fields = ["schema_title", "schema_description", "schema_type", "json_schema"]
|
|
266
|
+
for field in required_fields:
|
|
267
|
+
invalid_data_model = session_data_model.copy()
|
|
268
|
+
invalid_data_model.pop(field)
|
|
269
|
+
invalid_data_model["time_of_save"] = timestamp
|
|
270
|
+
invalid_data_model["time_of_removal"] = None
|
|
271
|
+
# rename the schema_name to make it unique
|
|
272
|
+
invalid_data_model["schema_name"] = f"invalid_{invalid_data_model['schema_name']}_missing_{field}"
|
|
273
|
+
invalid_data_models.append(invalid_data_model)
|
|
274
|
+
return invalid_data_models
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
# DomainModelDAOs
|
|
278
|
+
|
|
279
|
+
@pytest.fixture
|
|
280
|
+
def populated_domain_model_dao(empty_client, project, property_models, metamodels, data_models, timestamp):
|
|
281
|
+
dao = MongoDAO(empty_client, project, "domain_models", ["schema_name"])
|
|
282
|
+
for property_model in property_models:
|
|
283
|
+
dao.add(property_model, timestamp=timestamp)
|
|
284
|
+
for metamodel in metamodels:
|
|
285
|
+
dao.add(metamodel, timestamp=timestamp)
|
|
286
|
+
for data_model in data_models:
|
|
287
|
+
dao.add(data_model, timestamp=timestamp)
|
|
288
|
+
return dao
|
|
289
|
+
|
|
290
|
+
@pytest.fixture
|
|
291
|
+
def populated_domain_model_dao_with_invalid_models(empty_client, project, property_models, invalid_property_models, metamodels, data_models, invalid_data_models, timestamp):
|
|
292
|
+
dao = MongoDAO(empty_client, project, "domain_models", ["schema_name"])
|
|
293
|
+
for property_model in property_models:
|
|
294
|
+
dao.add(property_model, timestamp=timestamp)
|
|
295
|
+
for metamodel in metamodels:
|
|
296
|
+
dao.add(metamodel, timestamp=timestamp)
|
|
297
|
+
for data_model in data_models:
|
|
298
|
+
dao.add(data_model, timestamp=timestamp)
|
|
299
|
+
for property_model in invalid_property_models:
|
|
300
|
+
dao.add(property_model, timestamp=timestamp)
|
|
301
|
+
# add a property model with an invalid (text) json schema
|
|
302
|
+
invalid_json_schema_property_model = {
|
|
303
|
+
"schema_name": "invalid_json_schema",
|
|
304
|
+
"schema_title": "Invalid JSON Schema Model",
|
|
305
|
+
"schema_description": "A JSON Schema Model with invalid JSON",
|
|
306
|
+
"schema_type": "property_model",
|
|
307
|
+
"json_schema": "invalid json schema",
|
|
308
|
+
"time_of_save": timestamp,
|
|
309
|
+
"time_of_removal": None
|
|
310
|
+
}
|
|
311
|
+
dao._collection.insert_one(invalid_json_schema_property_model)
|
|
312
|
+
for data_model in invalid_data_models:
|
|
313
|
+
dao.add(data_model, timestamp=timestamp)
|
|
314
|
+
return dao
|
|
315
|
+
|
|
316
|
+
@pytest.fixture
|
|
317
|
+
def invalid_model_schema_names(invalid_property_models, invalid_data_models):
|
|
318
|
+
required_fields = ["schema_title", "schema_description", "schema_type", "json_schema"]
|
|
319
|
+
missing_field_names = [f"invalid_property_model_missing_{field}" for field in required_fields]
|
|
320
|
+
other_invalid_property_model_names = [property_model.get("schema_name") for property_model in invalid_property_models if property_model.get("schema_name") is not None]
|
|
321
|
+
invalid_data_model_names = [data_model.get("schema_name") for data_model in invalid_data_models if data_model.get("schema_name") is not None]
|
|
322
|
+
return missing_field_names + other_invalid_property_model_names + invalid_data_model_names
|
|
323
|
+
|
|
324
|
+
# ===================
|
|
325
|
+
# Records
|
|
326
|
+
# ===================
|
|
327
|
+
# Load the JSON file into a list of dictionaries
|
|
328
|
+
# valid records
|
|
329
|
+
records_path = test_data_path / "records.json"
|
|
330
|
+
with open(records_path, 'r') as file:
|
|
331
|
+
raw_records = json.load(file)
|
|
332
|
+
|
|
333
|
+
# invalid records
|
|
334
|
+
invalid_records_path = invalid_test_data_path / "records.json"
|
|
335
|
+
with open(invalid_records_path, 'r') as file:
|
|
336
|
+
raw_invalid_records = json.load(file)
|
|
337
|
+
|
|
338
|
+
# generate fixtures that provide individual records
|
|
339
|
+
for record in raw_records:
|
|
340
|
+
schema_ref, data_name = record["schema_ref"], record["data_name"]
|
|
341
|
+
namestring = f"{schema_ref}_{data_name}_record"
|
|
342
|
+
@pytest.fixture(name=namestring)
|
|
343
|
+
def _record_fixture(timestamp, record=record):
|
|
344
|
+
record["time_of_save"] = datetime_to_microseconds(timestamp)
|
|
345
|
+
record["time_of_removal"] = None
|
|
346
|
+
return record
|
|
347
|
+
globals()[namestring] = _record_fixture
|
|
348
|
+
|
|
349
|
+
@pytest.fixture(name="test_record")
|
|
350
|
+
def _test_record_fixture(timestamp):
|
|
351
|
+
record = {"schema_ref": "test_schema", "name": "test_name", "key1": "value1", "key2": "value2"}
|
|
352
|
+
record["time_of_save"] = datetime_to_microseconds(timestamp)
|
|
353
|
+
record["time_of_removal"] = None
|
|
354
|
+
return record
|
|
355
|
+
|
|
356
|
+
# generate a fixture that provides all the records
|
|
357
|
+
@pytest.fixture(name="records")
|
|
358
|
+
def _records_fixture(timestamp):
|
|
359
|
+
records = []
|
|
360
|
+
for record in raw_records:
|
|
361
|
+
record = record.copy()
|
|
362
|
+
record["time_of_save"] = datetime_to_microseconds(timestamp)
|
|
363
|
+
record["time_of_removal"] = None
|
|
364
|
+
records.append(record)
|
|
365
|
+
return records
|
|
366
|
+
|
|
367
|
+
# generate a fixture that provides all the invalid records
|
|
368
|
+
@pytest.fixture(name="invalid_records")
|
|
369
|
+
def _invalid_records_fixture(timestamp):
|
|
370
|
+
invalid_records = []
|
|
371
|
+
for record in raw_invalid_records:
|
|
372
|
+
record = record.copy()
|
|
373
|
+
record["time_of_save"] = datetime_to_microseconds(timestamp)
|
|
374
|
+
record["time_of_removal"] = None
|
|
375
|
+
invalid_records.append(record)
|
|
376
|
+
return invalid_records
|
|
377
|
+
|
|
378
|
+
def record_dao_factory(client, project):
|
|
379
|
+
return MongoDAO(client, project, "records", ["schema_ref", "data_name", "version_timestamp"])
|
|
380
|
+
|
|
381
|
+
@pytest.fixture
|
|
382
|
+
def populated_record_dao(empty_client, project, records, timestamp):
|
|
383
|
+
dao = record_dao_factory(empty_client, project)
|
|
384
|
+
for record in records:
|
|
385
|
+
dao.add(record, timestamp=timestamp, versioning_on=False)
|
|
386
|
+
return dao
|
|
387
|
+
|
|
388
|
+
@pytest.fixture
|
|
389
|
+
def populated_record_dao_with_invalid_records(empty_client, project, records, invalid_records, timestamp):
|
|
390
|
+
dao = record_dao_factory(empty_client, project)
|
|
391
|
+
for record in records:
|
|
392
|
+
dao.add(record, timestamp=timestamp, versioning_on=False)
|
|
393
|
+
for record in invalid_records:
|
|
394
|
+
dao.add(record, timestamp=timestamp, versioning_on=False)
|
|
395
|
+
return dao
|
|
396
|
+
|
|
397
|
+
# ===================
|
|
398
|
+
# FileSystemDAO
|
|
399
|
+
# ===================
|
|
400
|
+
# Load NetCDF files into list of xarray DataArray objects
|
|
401
|
+
|
|
402
|
+
def deserialize_dataarray(data_object):
|
|
403
|
+
"""Deserializes a data object.
|
|
404
|
+
Arguments:
|
|
405
|
+
data_object {dict} -- The data object to deserialize.
|
|
406
|
+
Returns:
|
|
407
|
+
dict -- The deserialized data object.
|
|
408
|
+
"""
|
|
409
|
+
attrs = data_object.attrs.copy()
|
|
410
|
+
for key, value in attrs.items():
|
|
411
|
+
if isinstance(value, str):
|
|
412
|
+
if value == 'True':
|
|
413
|
+
attrs[key] = True
|
|
414
|
+
elif value == 'False':
|
|
415
|
+
attrs[key] = False
|
|
416
|
+
elif value == 'None':
|
|
417
|
+
attrs[key] = None
|
|
418
|
+
elif value.startswith('{'):
|
|
419
|
+
attrs[key] = json.loads(value)
|
|
420
|
+
if isinstance(value, np.ndarray):
|
|
421
|
+
attrs[key] = value.tolist()
|
|
422
|
+
data_object.attrs = attrs
|
|
423
|
+
return data_object
|
|
424
|
+
|
|
425
|
+
netcdf_dir = test_data_path / "data_arrays"
|
|
426
|
+
netcdf_files = list(netcdf_dir.glob("*.nc"))
|
|
427
|
+
dataarrays = []
|
|
428
|
+
for filepath in netcdf_files:
|
|
429
|
+
dataarray = xr.open_dataarray(filepath)
|
|
430
|
+
dataarray = deserialize_dataarray(dataarray)
|
|
431
|
+
dataarrays.append(dataarray)
|
|
432
|
+
|
|
433
|
+
@pytest.fixture(name="dataarrays")
|
|
434
|
+
def _dataarrays_fixture():
|
|
435
|
+
return dataarrays
|
|
436
|
+
|
|
437
|
+
# make a fixture that provides a single dataarray for each file of the form {schema_ref}_{name}_dataarray
|
|
438
|
+
for dataarray in dataarrays:
|
|
439
|
+
try:
|
|
440
|
+
schema_ref, data_name = dataarray.attrs["schema_ref"], dataarray.attrs["data_name"]
|
|
441
|
+
except:
|
|
442
|
+
raise ValueError(f"DataArray.attrs {dataarray.attrs} does not have schema_ref and data_name attributes")
|
|
443
|
+
namestring = f"{schema_ref}__{data_name}__dataarray"
|
|
444
|
+
@pytest.fixture(name=namestring)
|
|
445
|
+
def _dataarray_fixture(dataarray=dataarray):
|
|
446
|
+
return dataarray
|
|
447
|
+
|
|
448
|
+
globals()[namestring] = _dataarray_fixture
|
|
449
|
+
|
|
450
|
+
# make a fixture that provides a new dataarray with a different name
|
|
451
|
+
@pytest.fixture(name="test_dataarray")
|
|
452
|
+
def _test_dataarray_fixture(timestamp):
|
|
453
|
+
dataarray = xr.DataArray([[1, 2, 3], [4, 5, 6]], dims=("x", "y"), coords={"x": [10, 20]})
|
|
454
|
+
dataarray.attrs["schema_ref"] = "test"
|
|
455
|
+
dataarray.attrs["data_name"] = "test"
|
|
456
|
+
dataarray.attrs["version_timestamp"] = 0
|
|
457
|
+
dataarray.attrs["time_of_save"] = datetime_to_microseconds(timestamp)
|
|
458
|
+
dataarray.attrs["time_of_removal"] = ""
|
|
459
|
+
return dataarray
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
class MockMutableModelHelper(AbstractMutableHelper):
|
|
463
|
+
def __init__(self, schema_ref: str, data_name: str, version_timestamp: datetime=None):
|
|
464
|
+
state = np.array([0])
|
|
465
|
+
attrs = {"schema_ref": schema_ref,
|
|
466
|
+
"data_name": data_name,
|
|
467
|
+
"version_timestamp": version_timestamp
|
|
468
|
+
}
|
|
469
|
+
super().__init__(attrs=attrs, state=state)
|
|
470
|
+
|
|
471
|
+
def train(self, iterations: int=1):
|
|
472
|
+
# add a number to the state
|
|
473
|
+
for i in range(iterations):
|
|
474
|
+
self.state = np.append(self.state, self.state[-1] + 1)
|
|
475
|
+
|
|
476
|
+
class MockMutableModelNumpyAdapter(AbstractDataFileAdapter):
|
|
477
|
+
|
|
478
|
+
def read_file(self, path):
|
|
479
|
+
with self.filesystem.open(path, mode='rb') as f:
|
|
480
|
+
idkwargs = self.path_to_id_kwargs(path)
|
|
481
|
+
helper = MockMutableModelHelper(**idkwargs)
|
|
482
|
+
helper.state = np.load(f)
|
|
483
|
+
return helper
|
|
484
|
+
|
|
485
|
+
def write_file(self, path, data_object):
|
|
486
|
+
with self.filesystem.open(path, mode='wb') as f:
|
|
487
|
+
np.save(f, data_object.state)
|
|
488
|
+
|
|
489
|
+
def get_id_kwargs(self, data_object):
|
|
490
|
+
return {"schema_ref": data_object.attrs.get("schema_ref"),
|
|
491
|
+
"data_name": data_object.attrs.get("data_name"),
|
|
492
|
+
"version_timestamp": data_object.attrs.get("version_timestamp") or 0
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
def path_to_id_kwargs(self, path):
|
|
496
|
+
base_name = upath.UPath(path).stem
|
|
497
|
+
schema_ref, data_name, version_string = base_name.split("__")
|
|
498
|
+
version_timestamp = int(version_string.split("_")[1])
|
|
499
|
+
return {"schema_ref": schema_ref,
|
|
500
|
+
"data_name": data_name,
|
|
501
|
+
"version_timestamp": microseconds_to_datetime(version_timestamp)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
@property
|
|
505
|
+
def file_extension(self):
|
|
506
|
+
return ".npy"
|
|
507
|
+
|
|
508
|
+
@property
|
|
509
|
+
def file_format(self):
|
|
510
|
+
return "Numpy"
|
|
511
|
+
|
|
512
|
+
@property
|
|
513
|
+
def data_object_type(self):
|
|
514
|
+
return type(MockMutableModelHelper("", ""))
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
# make a fixture that provides a MutableModelHelper object
|
|
518
|
+
@pytest.fixture(name="mutable_model_helper")
|
|
519
|
+
def _mutable_model_helper_fixture():
|
|
520
|
+
return MockMutableModelHelper(schema_ref="test", data_name="test")
|
|
521
|
+
|
|
522
|
+
@pytest.fixture(name="xarray_netcdf_adapter")
|
|
523
|
+
def _default_data_adapter_fixture():
|
|
524
|
+
return XarrayDataArrayNetCDFAdapter()
|
|
525
|
+
|
|
526
|
+
@pytest.fixture(name="xarray_zarr_adapter")
|
|
527
|
+
def _zarr_data_adapter_fixture():
|
|
528
|
+
return XarrayDataArrayZarrAdapter()
|
|
529
|
+
|
|
530
|
+
@pytest.fixture(name="model_numpy_adapter")
|
|
531
|
+
def _numpy_model_adapter_fixture():
|
|
532
|
+
return MockMutableModelNumpyAdapter()
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
# make a fixture that provides a populated file DAO
|
|
536
|
+
@pytest.fixture(name="populated_netcdf_file_dao")
|
|
537
|
+
def _populated_netcdf_file_dao_fixture(tmpdir, xarray_netcdf_adapter, dataarrays):
|
|
538
|
+
project_dir = str(tmpdir) + "/netcdf"
|
|
539
|
+
filesystem = LocalFileSystem(root=str(project_dir))
|
|
540
|
+
dao = FileSystemDAO(filesystem=filesystem,
|
|
541
|
+
project_dir=project_dir,
|
|
542
|
+
default_data_adapter=xarray_netcdf_adapter)
|
|
543
|
+
for dataarray in dataarrays:
|
|
544
|
+
dao.add(data_object=dataarray)
|
|
545
|
+
#TODO: add versioned objects with different data adapters
|
|
546
|
+
return dao
|
|
547
|
+
|
|
548
|
+
@pytest.fixture(name="populated_zarr_file_dao")
|
|
549
|
+
def _populated_zarr_file_dao_fixture(tmpdir, xarray_zarr_adapter, dataarrays):
|
|
550
|
+
project_dir = str(tmpdir) + "/zarr"
|
|
551
|
+
filesystem = LocalFileSystem(root=str(project_dir))
|
|
552
|
+
dao = FileSystemDAO(filesystem=filesystem,
|
|
553
|
+
project_dir=project_dir,
|
|
554
|
+
default_data_adapter=xarray_zarr_adapter)
|
|
555
|
+
for dataarray in dataarrays:
|
|
556
|
+
dao.add(data_object=dataarray)
|
|
557
|
+
#TODO: add versioned objects with different data adapters
|
|
558
|
+
return dao
|
|
559
|
+
|
|
560
|
+
@pytest.fixture(name="populated_numpy_file_dao")
|
|
561
|
+
def _populated_numpy_file_dao_fixture(tmpdir, model_numpy_adapter, mutable_model_helper, timestamp):
|
|
562
|
+
project_dir = str(tmpdir) + "/numpy"
|
|
563
|
+
filesystem = LocalFileSystem(root=str(project_dir))
|
|
564
|
+
dao = FileSystemDAO(filesystem = filesystem,
|
|
565
|
+
project_dir=project_dir,
|
|
566
|
+
default_data_adapter=model_numpy_adapter)
|
|
567
|
+
for i in range(1, 11):
|
|
568
|
+
mutable_model_helper.attrs["version_timestamp"] = timestamp + timedelta(seconds=i)
|
|
569
|
+
mutable_model_helper.train(i)
|
|
570
|
+
data_name = mutable_model_helper.attrs["data_name"]
|
|
571
|
+
schema_ref = mutable_model_helper.attrs["schema_ref"]
|
|
572
|
+
vts = mutable_model_helper.attrs["version_timestamp"]
|
|
573
|
+
if not dao.exists(data_name=data_name, schema_ref=schema_ref, version_timestamp=vts):
|
|
574
|
+
dao.add(data_object=mutable_model_helper)
|
|
575
|
+
return dao
|
|
576
|
+
|
|
577
|
+
@pytest.fixture(name="populated_file_dao")
|
|
578
|
+
def _populated_file_dao_fixture(tmpdir, dataarrays, xarray_netcdf_adapter, model_numpy_adapter, mutable_model_helper, timestamp):
|
|
579
|
+
project_dir = str(tmpdir)
|
|
580
|
+
filesystem = LocalFileSystem(root=str(project_dir))
|
|
581
|
+
dao = FileSystemDAO(filesystem=filesystem,
|
|
582
|
+
project_dir=project_dir,
|
|
583
|
+
default_data_adapter=xarray_netcdf_adapter)
|
|
584
|
+
for dataarray in dataarrays:
|
|
585
|
+
deserialize_dataarray(dataarray)
|
|
586
|
+
dao.add(data_object=dataarray)
|
|
587
|
+
for i in range(1, 11):
|
|
588
|
+
mutable_model_helper.attrs["version_timestamp"] = timestamp + timedelta(seconds=i)
|
|
589
|
+
mutable_model_helper.train(i)
|
|
590
|
+
dao.add(data_object=mutable_model_helper, data_adapter=model_numpy_adapter)
|
|
591
|
+
return dao
|
|
592
|
+
|
|
593
|
+
@pytest.fixture(name="file_dao_options")
|
|
594
|
+
def _file_dao_options_fixture(populated_netcdf_file_dao, populated_zarr_file_dao, populated_numpy_file_dao):
|
|
595
|
+
return {
|
|
596
|
+
"netcdf": populated_netcdf_file_dao,
|
|
597
|
+
"zarr": populated_zarr_file_dao,
|
|
598
|
+
"numpy": populated_numpy_file_dao
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
@pytest.fixture(name="data_adapter_options")
|
|
602
|
+
def _data_adapter_options_fixture(xarray_netcdf_adapter, xarray_zarr_adapter, model_numpy_adapter):
|
|
603
|
+
return {
|
|
604
|
+
"netcdf": xarray_netcdf_adapter,
|
|
605
|
+
"zarr": xarray_zarr_adapter,
|
|
606
|
+
"numpy": model_numpy_adapter
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
@pytest.fixture(name="new_object_options")
|
|
610
|
+
def _new_object_options_fixture(timestamp):
|
|
611
|
+
xarray = xr.DataArray([[1, 2, 3], [4, 5, 6]], dims=("x", "y"), coords={"x": [10, 20]}, attrs={"schema_ref": "new", "data_name": "new", "version_timestamp": None})
|
|
612
|
+
model = MockMutableModelHelper(schema_ref="new", data_name="new", version_timestamp=timestamp)
|
|
613
|
+
return {
|
|
614
|
+
"netcdf": xarray,
|
|
615
|
+
"zarr": xarray,
|
|
616
|
+
"numpy": model
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
# ===================
|
|
621
|
+
# InMemoryObjectDAO
|
|
622
|
+
# ===================
|
|
623
|
+
|
|
624
|
+
# make a fixture that provides a bunch of objects of varying types to be stored in memory
|
|
625
|
+
|
|
626
|
+
objects = [{"key1": "value1", "key2": "value2"},
|
|
627
|
+
[1, 2, 3],
|
|
628
|
+
"string",
|
|
629
|
+
True,
|
|
630
|
+
1,
|
|
631
|
+
1.0,
|
|
632
|
+
np.array([1, 2, 3]),
|
|
633
|
+
xr.DataArray([[1, 2, 3], [4, 5, 6]], dims=("x", "y"), coords={"x": [10, 20]}),
|
|
634
|
+
]
|
|
635
|
+
|
|
636
|
+
@pytest.fixture(name="objects")
|
|
637
|
+
def _objects_fixture():
|
|
638
|
+
return objects
|
|
639
|
+
|
|
640
|
+
def make_typestring(object):
|
|
641
|
+
return type(object).__name__.lower()
|
|
642
|
+
|
|
643
|
+
# make fixtures for each object type
|
|
644
|
+
for object in objects:
|
|
645
|
+
typestring = make_typestring(object)
|
|
646
|
+
namestring = typestring + "_object"
|
|
647
|
+
@pytest.fixture(name=namestring)
|
|
648
|
+
def _object_fixture(object=object):
|
|
649
|
+
return object
|
|
650
|
+
globals()[namestring] = _object_fixture
|
|
651
|
+
|
|
652
|
+
# make a populated in memory object DAO
|
|
653
|
+
@pytest.fixture
|
|
654
|
+
def populated_memory_dao(objects):
|
|
655
|
+
dao = InMemoryObjectDAO(dict())
|
|
656
|
+
for object in objects:
|
|
657
|
+
typestring = make_typestring(object)
|
|
658
|
+
dao.add(object, 'test_' + typestring )
|
|
659
|
+
return dao
|
|
660
|
+
|
|
661
|
+
@pytest.fixture
|
|
662
|
+
def test_object():
|
|
663
|
+
return np.zeros((3, 3))
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
# ==========================================================
|
|
667
|
+
# ==========================================================
|
|
668
|
+
# Repositories
|
|
669
|
+
# ==========================================================
|
|
670
|
+
# ==========================================================
|
|
671
|
+
|
|
672
|
+
# ===================
|
|
673
|
+
# DomainModelRepository
|
|
674
|
+
# ===================
|
|
675
|
+
|
|
676
|
+
@pytest.fixture
|
|
677
|
+
def populated_domain_repo(populated_domain_model_dao_with_invalid_models):
|
|
678
|
+
domain_repo = DomainModelRepository(model_dao=populated_domain_model_dao_with_invalid_models,
|
|
679
|
+
model_metaschema=domain_model_json_schema)
|
|
680
|
+
return domain_repo
|
|
681
|
+
|
|
682
|
+
@pytest.fixture
|
|
683
|
+
def populated_valid_only_domain_repo(populated_domain_model_dao):
|
|
684
|
+
domain_repo = DomainModelRepository(model_dao=populated_domain_model_dao,
|
|
685
|
+
model_metaschema=domain_model_json_schema)
|
|
686
|
+
return domain_repo
|
|
687
|
+
|
|
688
|
+
@pytest.fixture
|
|
689
|
+
def empty_domain_repo(empty_client, project):
|
|
690
|
+
dao = MongoDAO(empty_client, project, "domain_models", ["schema_name"])
|
|
691
|
+
domain_repo = DomainModelRepository(model_dao=dao,
|
|
692
|
+
model_metaschema=domain_model_json_schema)
|
|
693
|
+
return domain_repo
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
# ===================
|
|
697
|
+
# DataRepository
|
|
698
|
+
# ===================
|
|
699
|
+
@pytest.fixture
|
|
700
|
+
def populated_data_repo(populated_domain_repo, populated_record_dao, populated_file_dao, mutable_model_helper, model_numpy_adapter, timestamp):
|
|
701
|
+
data_repo = DataRepository(record_dao=populated_record_dao,
|
|
702
|
+
file_dao=populated_file_dao,
|
|
703
|
+
domain_repo=populated_domain_repo)
|
|
704
|
+
for i in range(1, 11):
|
|
705
|
+
mutable_model_helper.attrs["version_timestamp"] = timestamp + timedelta(seconds=i)
|
|
706
|
+
mutable_model_helper.attrs["schema_ref"] = "numpy_test"
|
|
707
|
+
mutable_model_helper.attrs["data_name"] = "numpy_test"
|
|
708
|
+
mutable_model_helper.attrs["has_file"] = True
|
|
709
|
+
mutable_model_helper.train(i)
|
|
710
|
+
data_repo.add(object=mutable_model_helper, data_adapter=model_numpy_adapter, versioning_on=True)
|
|
711
|
+
data_repo.clear_operation_history()
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
return data_repo
|
|
715
|
+
|
|
716
|
+
@pytest.fixture
|
|
717
|
+
def populated_data_repo_with_invalid_records(populated_domain_repo, populated_record_dao_with_invalid_records, populated_file_dao, mutable_model_helper, model_numpy_adapter, timestamp):
|
|
718
|
+
data_repo = DataRepository(record_dao=populated_record_dao_with_invalid_records,
|
|
719
|
+
file_dao=populated_file_dao,
|
|
720
|
+
domain_repo=populated_domain_repo)
|
|
721
|
+
for i in range(1, 11):
|
|
722
|
+
mutable_model_helper.attrs["version_timestamp"] = timestamp + timedelta(seconds=i)
|
|
723
|
+
mutable_model_helper.attrs["schema_ref"] = "numpy_test"
|
|
724
|
+
mutable_model_helper.attrs["data_name"] = "numpy_test"
|
|
725
|
+
mutable_model_helper.attrs["has_file"] = True
|
|
726
|
+
mutable_model_helper.train(i)
|
|
727
|
+
data_repo.add(object=mutable_model_helper, data_adapter=model_numpy_adapter, versioning_on=True)
|
|
728
|
+
sleep(0.001)
|
|
729
|
+
data_repo.clear_operation_history()
|
|
730
|
+
|
|
731
|
+
return data_repo
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
# ===================
|
|
736
|
+
# InMemoryObjectRepository
|
|
737
|
+
# ===================
|
|
738
|
+
@pytest.fixture
|
|
739
|
+
def populated_memory_repo(populated_record_repository, populated_memory_dao):
|
|
740
|
+
return InMemoryObjectRepository(populated_record_repository, populated_memory_dao)
|
|
741
|
+
|
|
742
|
+
# ===================
|
|
743
|
+
# Unit of Work
|
|
744
|
+
# ===================
|
|
745
|
+
@pytest.fixture(name="unit_of_work")
|
|
746
|
+
def _unit_of_work_provider_fixture(tmpdir):
|
|
747
|
+
mongo_client = mongomock.MongoClient()
|
|
748
|
+
og_filesystem = LocalFileSystem(root=str(tmpdir))
|
|
749
|
+
filesystem = DirFileSystem(tmpdir, og_filesystem)
|
|
750
|
+
memory_store = dict()
|
|
751
|
+
uow_provider = UnitOfWorkProvider(mongo_client, filesystem, memory_store)
|
|
752
|
+
unit_of_work = uow_provider("testproject")
|
|
753
|
+
with unit_of_work as uow:
|
|
754
|
+
for property_model in raw_property_models:
|
|
755
|
+
uow.domain_models.add(property_model)
|
|
756
|
+
for metamodel in raw_metamodels:
|
|
757
|
+
uow.domain_models.add(metamodel)
|
|
758
|
+
for data_model in raw_data_models:
|
|
759
|
+
uow.domain_models.add(data_model)
|
|
760
|
+
for record in raw_records:
|
|
761
|
+
if not record.get("has_file"):
|
|
762
|
+
uow.data.add(record)
|
|
763
|
+
for dataarray in dataarrays:
|
|
764
|
+
if not dataarray.attrs.get("schema_ref") == "test":
|
|
765
|
+
uow.data.add(dataarray)
|
|
766
|
+
uow.commit()
|
|
767
|
+
return uow
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
# ==========================================================
|
|
772
|
+
# ==========================================================
|
|
773
|
+
# Helpers
|
|
774
|
+
# ==========================================================
|
|
775
|
+
# ==========================================================
|
|
776
|
+
# TODO: add helpers
|
|
777
|
+
|
|
778
|
+
# ==========================================================
|
|
779
|
+
# ==========================================================
|
|
780
|
+
# Handlers
|
|
781
|
+
# ==========================================================
|
|
782
|
+
# ==========================================================
|
|
783
|
+
# TODO: add handlers
|
|
784
|
+
|
|
785
|
+
# ==========================================================
|
|
786
|
+
# ==========================================================
|
|
787
|
+
# Dependency Injection
|
|
788
|
+
# ==========================================================
|
|
789
|
+
# ==========================================================
|
|
790
|
+
|
|
791
|
+
# ===================
|
|
792
|
+
# Handler Factory
|
|
793
|
+
# ===================
|
|
794
|
+
# TODO: add handler factory
|
|
795
|
+
|
|
796
|
+
# ===================
|
|
797
|
+
# Project Container
|
|
798
|
+
# ===================
|
|
799
|
+
# TODO: add project container
|