pastastore 1.10.2__py3-none-any.whl → 1.12.0__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.
@@ -0,0 +1,393 @@
1
+ # ruff: noqa: D100 D103
2
+ import pytest
3
+ from conftest import for_connectors
4
+
5
+ import pastastore as pst
6
+
7
+ pst.get_color_logger("DEBUG", logger_name="pastastore")
8
+
9
+
10
+ @pytest.fixture(scope="module")
11
+ def pstore_with_models(pstore):
12
+ """
13
+ Fixture that creates models for oseries1 and oseries2.
14
+
15
+ This provides a pastastore with two models ready for testing parallel-safe
16
+ operations and time series link updates.
17
+ """
18
+ # Create and add model for oseries1
19
+ ml1 = pstore.create_model("oseries1")
20
+ ml1.solve(report=False)
21
+ pstore.add_model(ml1)
22
+
23
+ # Create and add model for oseries2
24
+ ml2 = pstore.create_model("oseries2")
25
+ ml2.solve(report=False)
26
+ pstore.add_model(ml2)
27
+ # trigger update to start fresh
28
+ _ = pstore.conn.oseries_models
29
+ # ensure clean start
30
+ pstore.conn._trigger_links_update_if_needed()
31
+ yield pstore
32
+
33
+ # Cleanup
34
+ if "oseries1" in pstore.model_names:
35
+ pstore.del_model("oseries1")
36
+ if "oseries2" in pstore.model_names:
37
+ pstore.del_model("oseries2")
38
+
39
+
40
+ class TestSingleThreadOperations:
41
+ """Test single-thread add_model operations for all connector types."""
42
+
43
+ def test_oseries_models_triggers_update(self, pstore_with_models):
44
+ """Test that accessing oseries_models triggers update of added models."""
45
+ # Initially, _added_models should be empty
46
+ assert len(pstore_with_models.conn._added_models) == 0
47
+ # add model
48
+ ml = pstore_with_models.create_model("oseries3")
49
+ pstore_with_models.add_model(ml)
50
+ # Access oseries_models to trigger update
51
+ _ = pstore_with_models.conn.oseries_models
52
+ # After update, _added_models should be empty
53
+ assert len(pstore_with_models.conn._added_models) == 0
54
+ # cleanup
55
+ pstore_with_models.del_model("oseries3")
56
+
57
+ def test_stresses_models_triggers_update(self, pstore_with_models):
58
+ """Test that accessing stresses_models triggers update of added models."""
59
+ # initially, _added_models should be empty
60
+ assert len(pstore_with_models.conn._added_models) == 0
61
+ # add model
62
+ ml = pstore_with_models.create_model("oseries3")
63
+ pstore_with_models.add_model(ml)
64
+ # access stresses_models to trigger update
65
+ _ = pstore_with_models.conn.stresses_models
66
+ # after update, _added_models should be empty
67
+ assert len(pstore_with_models.conn._added_models) == 0
68
+ # cleanup
69
+ pstore_with_models.del_model("oseries3")
70
+
71
+ def test_oseries_with_models_triggers_update(self, pstore_with_models):
72
+ """Test that accessing oseries_with_models triggers update of added models."""
73
+ # initially, _added_models should be empty
74
+ assert len(pstore_with_models.conn._added_models) == 0
75
+ # add model
76
+ ml = pstore_with_models.create_model("oseries3")
77
+ pstore_with_models.add_model(ml)
78
+ # access oseries_models to trigger update
79
+ _ = pstore_with_models.conn.oseries_with_models
80
+ # after update, _added_models should be empty
81
+ assert len(pstore_with_models.conn._added_models) == 0
82
+ # cleanup
83
+ pstore_with_models.del_model("oseries3")
84
+
85
+ def test_stresses_with_models_triggers_update(self, pstore_with_models):
86
+ """Test that accessing stresses_with_models triggers update of added models."""
87
+ # initially, _added_models should be empty
88
+ assert len(pstore_with_models.conn._added_models) == 0
89
+ # add model
90
+ ml = pstore_with_models.create_model("oseries3")
91
+ pstore_with_models.add_model(ml)
92
+ # access stresses_with_models to trigger update
93
+ _ = pstore_with_models.conn.stresses_with_models
94
+ # after update, _added_models should be empty
95
+ assert len(pstore_with_models.conn._added_models) == 0
96
+ # cleanup
97
+ pstore_with_models.del_model("oseries3")
98
+
99
+ def test_add_model_appends_to_added_models_list(self, pstore_with_models):
100
+ """Test that add_model appends to _added_models list."""
101
+ # Check internal state, should contain two models
102
+ assert len(pstore_with_models.conn._added_models) == 0
103
+ # Create a new model
104
+ ml = pstore_with_models.create_model("oseries3")
105
+ # Add model
106
+ pstore_with_models.add_model(ml)
107
+ # Verify the model name was added to _added_models
108
+ assert "oseries3" in pstore_with_models.conn._added_models
109
+ # check oseries_models (triggers link update)
110
+ assert "oseries3" in pstore_with_models.oseries_models
111
+ # check that _added_models is now empty after update
112
+ assert len(pstore_with_models.conn._added_models) == 0
113
+ # Cleanup
114
+ pstore_with_models.del_model("oseries3")
115
+
116
+ def test_del_model_deletes_from_added_models_list(self, pstore_with_models):
117
+ """Test that del_model deletes from non-empty _added_models list."""
118
+ # Check internal state, should be empty
119
+ assert len(pstore_with_models.conn._added_models) == 0
120
+ # Create a new model
121
+ ml = pstore_with_models.create_model("oseries3")
122
+ # Add model
123
+ pstore_with_models.add_model(ml)
124
+ pstore_with_models.del_model("oseries3")
125
+ # check that _added_models is now empty after update
126
+ assert len(pstore_with_models.conn._added_models) == 0
127
+
128
+
129
+ class TestParallelButNotReally:
130
+ """Test internal update flag behavior (for parallel)."""
131
+
132
+ @for_connectors(connectors=["pas", "arcticdb"])
133
+ def test_parallel_add_model_sets_update_flags(self, pstore_with_models):
134
+ """Test parallel_safe adds set update flags for parallel connectors."""
135
+
136
+ def add_model(name):
137
+ """Add model using global pstore."""
138
+ ml = pstore_with_models.get_models(name)
139
+ ml.solve(report=False)
140
+ pstore_with_models.add_model(ml, overwrite=True)
141
+
142
+ pstore_with_models.apply(
143
+ func=add_model,
144
+ names=["oseries1", "oseries2"],
145
+ libname="models",
146
+ parallel=False,
147
+ )
148
+
149
+ # check update parameters are set to True
150
+ assert pstore_with_models.conn._oseries_links_need_update.value is True
151
+ assert pstore_with_models.conn._stresses_links_need_update.value is True
152
+
153
+ # trigger update
154
+ pstore_with_models.conn._trigger_links_update_if_needed()
155
+
156
+ # after update, flags should be False
157
+ assert pstore_with_models.conn._oseries_links_need_update.value is False
158
+ assert pstore_with_models.conn._stresses_links_need_update.value is False
159
+
160
+ @for_connectors(connectors=["pas", "arcticdb"])
161
+ def test_oseries_models_triggers_update(self, pstore_with_models):
162
+ """Test that accessing oseries_models triggers update of added models."""
163
+ # Initially, _added_models should be empty
164
+ assert len(pstore_with_models.conn._added_models) == 0
165
+
166
+ def add_model(name):
167
+ """Add model using pstore."""
168
+ ml = pstore_with_models.create_model(name)
169
+ pstore_with_models.add_model(ml, overwrite=True)
170
+
171
+ pstore_with_models.apply(
172
+ func=add_model,
173
+ names=["oseries1", "oseries2"],
174
+ libname="oseries",
175
+ parallel=False,
176
+ )
177
+
178
+ # check update parameters are set to True
179
+ assert pstore_with_models.conn._oseries_links_need_update.value is True
180
+ assert pstore_with_models.conn._stresses_links_need_update.value is True
181
+
182
+ # trigger update
183
+ om = pstore_with_models.oseries_models
184
+
185
+ # check if result is correct
186
+ assert om["oseries1"] == ["oseries1"]
187
+ assert om["oseries2"] == ["oseries2"]
188
+
189
+ # after update, flags should be False
190
+ assert pstore_with_models.conn._oseries_links_need_update.value is False
191
+ assert pstore_with_models.conn._stresses_links_need_update.value is False
192
+
193
+ @for_connectors(connectors=["pas", "arcticdb"])
194
+ def test_stresses_models_triggers_update(self, pstore_with_models):
195
+ """Test that accessing stresses_models triggers update of added models."""
196
+ # Initially, _added_models should be empty
197
+ assert len(pstore_with_models.conn._added_models) == 0
198
+
199
+ def add_model(name):
200
+ """Add model using pstore."""
201
+ ml = pstore_with_models.create_model(name)
202
+ pstore_with_models.add_model(ml, overwrite=True)
203
+
204
+ pstore_with_models.apply(
205
+ func=add_model,
206
+ names=["oseries1", "oseries2"],
207
+ libname="oseries",
208
+ parallel=False,
209
+ )
210
+
211
+ # check update parameters are set to True
212
+ assert pstore_with_models.conn._oseries_links_need_update.value is True
213
+ assert pstore_with_models.conn._stresses_links_need_update.value is True
214
+
215
+ # trigger update
216
+ sm = pstore_with_models.stresses_models
217
+
218
+ # check if result is correct
219
+ assert sm["prec1"] == ["oseries1"]
220
+ assert sm["prec2"] == ["oseries2"]
221
+ assert sm["evap1"] == ["oseries1"]
222
+ assert sm["evap2"] == ["oseries2"]
223
+
224
+ # after update, flags should be False
225
+ assert pstore_with_models.conn._oseries_links_need_update.value is False
226
+ assert pstore_with_models.conn._stresses_links_need_update.value is False
227
+
228
+ @for_connectors(connectors=["pas", "arcticdb"])
229
+ def test_oseries_with_models_triggers_update(self, pstore_with_models):
230
+ """Test that accessing oseries_with_models triggers update of added models."""
231
+ # Initially, _added_models should be empty
232
+ assert len(pstore_with_models.conn._added_models) == 0
233
+
234
+ def add_model(name):
235
+ """Add model using pstore."""
236
+ ml = pstore_with_models.create_model(name)
237
+ pstore_with_models.add_model(ml, overwrite=True)
238
+
239
+ pstore_with_models.apply(
240
+ func=add_model,
241
+ names=["oseries1", "oseries2"],
242
+ libname="oseries",
243
+ parallel=False,
244
+ )
245
+
246
+ # check update parameters are set to True
247
+ assert pstore_with_models.conn._oseries_links_need_update.value is True
248
+ assert pstore_with_models.conn._stresses_links_need_update.value is True
249
+
250
+ # trigger update
251
+ owm = pstore_with_models.oseries_with_models
252
+
253
+ # check if result is correct
254
+ assert "oseries1" in owm
255
+ assert "oseries2" in owm
256
+
257
+ # after update, flags should be False
258
+ assert pstore_with_models.conn._oseries_links_need_update.value is False
259
+ assert pstore_with_models.conn._stresses_links_need_update.value is False
260
+
261
+ @for_connectors(connectors=["pas", "arcticdb"])
262
+ def test_stresses_with_models_triggers_update(self, pstore_with_models):
263
+ """Test that accessing stresses_with_models triggers update of added models."""
264
+ # Initially, _added_models should be empty
265
+ assert len(pstore_with_models.conn._added_models) == 0
266
+
267
+ def add_model(name):
268
+ """Add model using pstore."""
269
+ ml = pstore_with_models.create_model(name)
270
+ pstore_with_models.add_model(ml, overwrite=True)
271
+
272
+ pstore_with_models.apply(
273
+ func=add_model,
274
+ names=["oseries1", "oseries2"],
275
+ libname="oseries",
276
+ parallel=False,
277
+ )
278
+
279
+ # check update parameters are set to True
280
+ assert pstore_with_models.conn._oseries_links_need_update.value is True
281
+ assert pstore_with_models.conn._stresses_links_need_update.value is True
282
+
283
+ # check if result is correct
284
+ swm = pstore_with_models.stresses_with_models
285
+
286
+ assert "prec1" in swm
287
+ assert "prec2" in swm
288
+ assert "evap1" in swm
289
+ assert "evap2" in swm
290
+
291
+ # after update, flags should be False
292
+ assert pstore_with_models.conn._oseries_links_need_update.value is False
293
+ assert pstore_with_models.conn._stresses_links_need_update.value is False
294
+
295
+
296
+ def add_model_pas(name):
297
+ """Add model using pstore."""
298
+ ml = ppstore.create_model(name)
299
+ ppstore.add_model(ml, overwrite=True)
300
+
301
+
302
+ def add_model_arcticdb(name):
303
+ """Add model using pstore."""
304
+ ppstore = pst.PastaStore(conn)
305
+ ml = ppstore.create_model(name)
306
+ conn.add_model(ml, overwrite=True)
307
+
308
+
309
+ def setup_parallel_pstore(conn_type, data1, data2):
310
+ global conn
311
+ global ppstore
312
+
313
+ if conn_type == "arcticdb":
314
+ name = "paralleldb"
315
+ uri = "lmdb://./tests/data/arcticdb/"
316
+ conn = pst.ArcticDBConnector(name, uri)
317
+ elif conn_type == "pas":
318
+ name = "paralleldb"
319
+ conn = pst.PasConnector(name, "./tests/data/pas")
320
+ else:
321
+ raise ValueError("Unrecognized parameter!")
322
+
323
+ ppstore = pst.PastaStore(conn)
324
+ # dataset 1
325
+ ppstore.add_oseries(data1["oseries1"], "oseries1", metadata=data1["oseries1_meta"])
326
+ ppstore.add_stress(
327
+ data1["prec1"], "prec1", kind="prec", metadata=data1["prec1_meta"]
328
+ )
329
+ ppstore.add_stress(
330
+ data1["evap1"], "evap1", kind="evap", metadata=data1["evap1_meta"]
331
+ )
332
+
333
+ # dataset 2
334
+ ppstore.add_oseries(data2["oseries2"], "oseries2", metadata=data2["oseries2_meta"])
335
+ ppstore.add_stress(
336
+ data2["prec2"], "prec2", kind="prec", metadata=data2["prec2_meta"]
337
+ )
338
+ ppstore.add_stress(
339
+ data2["evap2"], "evap2", kind="evap", metadata=data2["evap2_meta"]
340
+ )
341
+ return ppstore
342
+
343
+
344
+ @pytest.mark.parametrize("conn_type", ["pas", "arcticdb"])
345
+ def test_parallel_add_model(conn_type, data1, data2):
346
+ """Test that accessing stresses_with_models triggers update of added models."""
347
+ ppstore = setup_parallel_pstore(conn_type, data1, data2)
348
+
349
+ if conn_type == "arcticdb":
350
+ func = add_model_arcticdb
351
+ elif conn_type == "pas":
352
+ func = add_model_pas
353
+ else:
354
+ raise ValueError("Unrecognized parameter!")
355
+ try:
356
+ # Initially, _added_models should be empty
357
+ assert len(ppstore.conn._added_models) == 0
358
+
359
+ ppstore.apply(
360
+ func=func,
361
+ names=["oseries1", "oseries2"],
362
+ libname="oseries",
363
+ parallel=True,
364
+ max_workers=1,
365
+ )
366
+
367
+ # check update parameters are set to False, since after parallel these are
368
+ # recomputed automatically
369
+ assert ppstore.conn._oseries_links_need_update.value is False
370
+ assert ppstore.conn._stresses_links_need_update.value is False
371
+
372
+ # check if result is correct
373
+ om = ppstore.oseries_models
374
+ owm = ppstore.oseries_with_models
375
+ sm = ppstore.stresses_models
376
+ swm = ppstore.stresses_with_models
377
+ assert "oseries1" in owm
378
+ assert "oseries2" in owm
379
+ assert "oseries1" in om
380
+ assert "oseries2" in om
381
+ assert "oseries1" in om["oseries1"]
382
+ assert "oseries2" in om["oseries2"]
383
+ assert "prec1" in swm
384
+ assert "prec2" in swm
385
+ assert "evap1" in swm
386
+ assert "evap2" in swm
387
+ assert "oseries1" in sm["prec1"]
388
+ assert "oseries2" in sm["prec2"]
389
+ assert "oseries1" in sm["evap1"]
390
+ assert "oseries2" in sm["evap2"]
391
+
392
+ finally:
393
+ pst.util.delete_pastastore(ppstore)
@@ -1,28 +0,0 @@
1
- docs/conf.py,sha256=XcZUTmn9fGDhhu8k3mpaLu435SpIRNpABADCCTJJuag,6291
2
- pastastore/__init__.py,sha256=cWwG9-YeiI4aOU0CDBGKbQgmKmmkcPd64YwPq2rRGt0,416
3
- pastastore/base.py,sha256=ng64KGuKo2iMLjL0H7qG3NVNvXPwMGJBf3oLtQbt6DQ,48264
4
- pastastore/connectors.py,sha256=hum8KkPi28B3XBsKL_RghRCsZndf-jeFlb4baTvyDG4,50197
5
- pastastore/datasets.py,sha256=FHVfmKqb8beEs9NONsWrCoJY37BmlvFLSEQ1VAFmE8A,6415
6
- pastastore/plotting.py,sha256=ygKXdi42sPLaehze4EjU8kRE2Dk46wVxSkB9RJ2Re84,54535
7
- pastastore/store.py,sha256=Fs_WCEGqafOKm3whLUR54tqXL1dL3FdzwxNI1DSZ2KI,69272
8
- pastastore/styling.py,sha256=0IEp_r-SpcaslShAZvZV6iuEhTG_YzNq-ad8krib3U0,2304
9
- pastastore/util.py,sha256=31dzHaK6xdFHGDkYh49qGBq1dGel2m9r7i797S3WUpQ,28505
10
- pastastore/version.py,sha256=2Y6_CKnmHYQTxRyvvUEW2519LmIeszWd-0NYpCRyV6M,1206
11
- pastastore/yaml_interface.py,sha256=n6zjQ7ENrUvxszb6zE-jPLa-XVsoEOTJHQmRV1_fFt0,30818
12
- pastastore/extensions/__init__.py,sha256=lCN9xfX1qefUzUbE2FQ12c6NjLbf5HoNo-D8cGb5CTw,461
13
- pastastore/extensions/accessor.py,sha256=kftQM6dqMDoySbyTKcvmkjC5gJRp465KA18G4NVXUO0,367
14
- pastastore/extensions/hpd.py,sha256=i9Ty9GyRyrtY0uqjMpWheH33oYDQM8WMmygaDEPx-w4,28581
15
- pastastore-1.10.2.dist-info/licenses/LICENSE,sha256=MB_6p4kXDCUsYNjslcMByBu6i7wMNRKPC36JnhzpN4o,1087
16
- tests/conftest.py,sha256=TB0ZUH1m45gvQd_EZO7iudvhFw4JA-8rTJ71GT6Nf1w,5061
17
- tests/test_001_import.py,sha256=g8AaJzWZ088A4B30_w-MrDfAVeeg8m78l--j7Onsklc,208
18
- tests/test_002_connectors.py,sha256=X7IbxZZXBYd2UT8B5gu0_Jw--3Twe7KHjSBbmMwNnRk,8193
19
- tests/test_003_pastastore.py,sha256=nhcUJHC2KiF9KREP_2uj_T2skKooUk13T1EVtkbwQnM,10051
20
- tests/test_004_yaml.py,sha256=3hMNjb9s0S2rbmpyEjW6FDRAxfUZS_U1qoPl4wB-cCo,4440
21
- tests/test_005_maps_plots.py,sha256=L0ppGf-cudsrdxteWy3qsV4We96DW4bCBE7c6jEm6aM,1866
22
- tests/test_006_benchmark.py,sha256=VZG0bY7uz8DkfIZTgRCzkEDG8rguBEt_-mdGSMQLN2w,4930
23
- tests/test_007_hpdextension.py,sha256=1QNUahq3hzqxjKbzsjofi9Yuyqe_oDGL0vWp6iouYe4,3004
24
- tests/test_008_stressmodels.py,sha256=733fyCvuzjKcaLjvSMt5dTTLp-T4alzNJAToSxTIUug,4003
25
- pastastore-1.10.2.dist-info/METADATA,sha256=8oLyVDQ95wA9wzSxBR29fMg2s81HjlvXGenukFxx2NA,7662
26
- pastastore-1.10.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- pastastore-1.10.2.dist-info/top_level.txt,sha256=1bgyMk1p23f04RK83Jju2_YAQBwyoQD_fInxoPB4YRw,22
28
- pastastore-1.10.2.dist-info/RECORD,,