fmu-settings 0.3.0__tar.gz → 0.3.2__tar.gz
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 fmu-settings might be problematic. Click here for more details.
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/PKG-INFO +1 -1
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_resources/lock_manager.py +13 -3
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_resources/pydantic_resource_manager.py +11 -4
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_version.py +3 -3
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu_settings.egg-info/PKG-INFO +1 -1
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/tests/test_fmu_dir.py +2 -2
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/tests/test_resources/test_lock_manager.py +41 -10
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/tests/test_resources/test_resource_managers.py +56 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/.coveragerc +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/.github/pull_request_template.md +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/.github/workflows/ci.yml +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/.github/workflows/codeql.yml +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/.github/workflows/publish.yml +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/.gitignore +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/CONTRIBUTING.md +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/LICENSE +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/README.md +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/SECURITY.md +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/pyproject.toml +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/setup.cfg +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/__init__.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/__init__.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_fmu_dir.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_init.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_logging.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_resources/__init__.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_resources/config_managers.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/models/__init__.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/models/_enums.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/models/_mappings.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/models/lock_info.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/models/project_config.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/models/user_config.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/py.typed +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/types.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu_settings.egg-info/SOURCES.txt +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu_settings.egg-info/dependency_links.txt +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu_settings.egg-info/requires.txt +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu_settings.egg-info/top_level.txt +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/tests/conftest.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/tests/test_init.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/tests/test_resources/test_project_config.py +0 -0
- {fmu_settings-0.3.0 → fmu_settings-0.3.2}/tests/test_resources/test_user_config.py +0 -0
|
@@ -153,7 +153,17 @@ class LockManager(PydanticResourceManager[LockInfo]):
|
|
|
153
153
|
temp_path.unlink()
|
|
154
154
|
|
|
155
155
|
def is_locked(self: Self) -> bool:
|
|
156
|
-
"""Returns whether or not the lock is
|
|
156
|
+
"""Returns whether or not the lock is locked by anyone.
|
|
157
|
+
|
|
158
|
+
This does a force load on the lock file.
|
|
159
|
+
"""
|
|
160
|
+
lock_info = self._safe_load(force=True)
|
|
161
|
+
if not lock_info:
|
|
162
|
+
return False
|
|
163
|
+
return time.time() < lock_info.expires_at
|
|
164
|
+
|
|
165
|
+
def is_acquired(self: Self) -> bool:
|
|
166
|
+
"""Returns whether or not the lock is currently acquired by this instance."""
|
|
157
167
|
if self._cache is None or self._acquired_at is None:
|
|
158
168
|
return False
|
|
159
169
|
return self._is_mine(self._cache) and not self._is_stale()
|
|
@@ -219,13 +229,13 @@ class LockManager(PydanticResourceManager[LockInfo]):
|
|
|
219
229
|
and lock_info.acquired_at == self._acquired_at
|
|
220
230
|
)
|
|
221
231
|
|
|
222
|
-
def _safe_load(self: Self) -> LockInfo | None:
|
|
232
|
+
def _safe_load(self: Self, force: bool = False) -> LockInfo | None:
|
|
223
233
|
"""Load lock info, returning None if corrupted.
|
|
224
234
|
|
|
225
235
|
Because this file does not exist in a static state, wrap around loading it.
|
|
226
236
|
"""
|
|
227
237
|
try:
|
|
228
|
-
return self.load()
|
|
238
|
+
return self.load(force=force)
|
|
229
239
|
except Exception:
|
|
230
240
|
return None
|
|
231
241
|
|
{fmu_settings-0.3.0 → fmu_settings-0.3.2}/src/fmu/settings/_resources/pydantic_resource_manager.py
RENAMED
|
@@ -48,11 +48,14 @@ class PydanticResourceManager(Generic[T]):
|
|
|
48
48
|
"""Returns whether or not the resource exists."""
|
|
49
49
|
return self.path.exists()
|
|
50
50
|
|
|
51
|
-
def load(self: Self, force: bool = False) -> T:
|
|
52
|
-
"""Loads the
|
|
51
|
+
def load(self: Self, force: bool = False, store_cache: bool = True) -> T:
|
|
52
|
+
"""Loads the resource from disk and validates it as a Pydantic model.
|
|
53
53
|
|
|
54
54
|
Args:
|
|
55
|
-
force: Force a re-read even if the file is already cached
|
|
55
|
+
force: Force a re-read even if the file is already cached.
|
|
56
|
+
store_cache: Whether or not to cache the loaded model internally. This is
|
|
57
|
+
best used with 'force=True' because if a model is already stored in
|
|
58
|
+
_cache it will be returned without re-loading. Default True.
|
|
56
59
|
|
|
57
60
|
Returns:
|
|
58
61
|
Validated Pydantic model
|
|
@@ -71,7 +74,11 @@ class PydanticResourceManager(Generic[T]):
|
|
|
71
74
|
try:
|
|
72
75
|
content = self.fmu_dir.read_text_file(self.relative_path)
|
|
73
76
|
data = json.loads(content)
|
|
74
|
-
|
|
77
|
+
validated_model = self.model_class.model_validate(data)
|
|
78
|
+
if store_cache:
|
|
79
|
+
self._cache = validated_model
|
|
80
|
+
else:
|
|
81
|
+
return validated_model
|
|
75
82
|
except ValidationError as e:
|
|
76
83
|
raise ValueError(
|
|
77
84
|
f"Invalid content in resource file for '{self.__class__.__name__}: "
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.3.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
31
|
+
__version__ = version = '0.3.2'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 2)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g9ea88b68f'
|
|
@@ -333,7 +333,7 @@ def test_acquire_lock_on_project_fmu(
|
|
|
333
333
|
) -> None:
|
|
334
334
|
"""Tests that a lock can be acquired on the project dir."""
|
|
335
335
|
fmu_dir._lock.acquire()
|
|
336
|
-
assert fmu_dir._lock.
|
|
336
|
+
assert fmu_dir._lock.is_acquired()
|
|
337
337
|
assert fmu_dir._lock.exists
|
|
338
338
|
assert (fmu_dir.path / ".lock").exists()
|
|
339
339
|
|
|
@@ -343,6 +343,6 @@ def test_acquire_lock_on_user_fmu(
|
|
|
343
343
|
) -> None:
|
|
344
344
|
"""Tests that a lock can be acquired on the user dir."""
|
|
345
345
|
user_fmu_dir._lock.acquire()
|
|
346
|
-
assert user_fmu_dir._lock.
|
|
346
|
+
assert user_fmu_dir._lock.is_acquired()
|
|
347
347
|
assert user_fmu_dir._lock.exists
|
|
348
348
|
assert (user_fmu_dir.path / ".lock").exists()
|
|
@@ -95,6 +95,7 @@ def test_lock_acquire_raises_if_already_acquired(fmu_dir: ProjectFMUDirectory) -
|
|
|
95
95
|
lock = LockManager(fmu_dir)
|
|
96
96
|
lock.acquire()
|
|
97
97
|
assert lock.is_locked()
|
|
98
|
+
assert lock.is_acquired()
|
|
98
99
|
with pytest.raises(LockError, match="Lock already acquired"):
|
|
99
100
|
lock.acquire()
|
|
100
101
|
|
|
@@ -190,6 +191,7 @@ def test_lock_acquire_over_expired_lock(fmu_dir: ProjectFMUDirectory) -> None:
|
|
|
190
191
|
stale_lock = LockManager(fmu_dir, timeout_seconds=-1) # Expired
|
|
191
192
|
stale_lock.acquire()
|
|
192
193
|
assert stale_lock.is_locked() is False
|
|
194
|
+
assert stale_lock.is_acquired() is False
|
|
193
195
|
assert stale_lock._is_stale() is True
|
|
194
196
|
stale_lock_info = stale_lock.load()
|
|
195
197
|
|
|
@@ -198,6 +200,7 @@ def test_lock_acquire_over_expired_lock(fmu_dir: ProjectFMUDirectory) -> None:
|
|
|
198
200
|
lock_info = lock.load()
|
|
199
201
|
|
|
200
202
|
assert lock.is_locked()
|
|
203
|
+
assert lock.is_acquired()
|
|
201
204
|
assert stale_lock.path == lock.path
|
|
202
205
|
assert lock_info != stale_lock_info
|
|
203
206
|
|
|
@@ -385,27 +388,55 @@ def test_try_acquire_fails_when_linking_temp_file(
|
|
|
385
388
|
def test_is_locked_expected(
|
|
386
389
|
fmu_dir: ProjectFMUDirectory, monkeypatch: MonkeyPatch
|
|
387
390
|
) -> None:
|
|
388
|
-
"""Tests is_locked under expected conditions."""
|
|
391
|
+
"""Tests is_locked under expected, simple conditions."""
|
|
389
392
|
lock = LockManager(fmu_dir)
|
|
390
393
|
assert lock.is_locked() is False
|
|
391
394
|
lock.acquire()
|
|
392
395
|
assert lock.is_locked() is True
|
|
396
|
+
lock.release()
|
|
397
|
+
assert lock.is_locked() is False
|
|
393
398
|
|
|
394
399
|
|
|
395
|
-
def
|
|
400
|
+
def test_is_locked_by_other_process(
|
|
396
401
|
fmu_dir: ProjectFMUDirectory, monkeypatch: MonkeyPatch
|
|
397
402
|
) -> None:
|
|
398
|
-
"""Tests is_locked
|
|
403
|
+
"""Tests is_locked when another process has the lock."""
|
|
399
404
|
lock = LockManager(fmu_dir)
|
|
400
405
|
assert lock.is_locked() is False
|
|
401
|
-
|
|
406
|
+
with patch("os.getpid", return_value=-1234):
|
|
407
|
+
lock.acquire()
|
|
408
|
+
|
|
402
409
|
assert lock.is_locked() is True
|
|
410
|
+
|
|
411
|
+
with patch("os.getpid", return_value=-1234):
|
|
412
|
+
lock.release()
|
|
413
|
+
assert lock.is_locked() is False
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def test_is_acquired_expected(
|
|
417
|
+
fmu_dir: ProjectFMUDirectory, monkeypatch: MonkeyPatch
|
|
418
|
+
) -> None:
|
|
419
|
+
"""Tests is_acquired under expected conditions."""
|
|
420
|
+
lock = LockManager(fmu_dir)
|
|
421
|
+
assert lock.is_acquired() is False
|
|
422
|
+
lock.acquire()
|
|
423
|
+
assert lock.is_acquired() is True
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def test_is_acquired_unexpected_members(
|
|
427
|
+
fmu_dir: ProjectFMUDirectory, monkeypatch: MonkeyPatch
|
|
428
|
+
) -> None:
|
|
429
|
+
"""Tests is_acquired under expected member conditions."""
|
|
430
|
+
lock = LockManager(fmu_dir)
|
|
431
|
+
assert lock.is_acquired() is False
|
|
432
|
+
lock.acquire()
|
|
433
|
+
assert lock.is_acquired() is True
|
|
403
434
|
lock_info = lock._cache
|
|
404
435
|
lock._cache = None
|
|
405
|
-
assert lock.
|
|
436
|
+
assert lock.is_acquired() is False
|
|
406
437
|
lock._cache = lock_info
|
|
407
438
|
lock._acquired_at = None
|
|
408
|
-
assert lock.
|
|
439
|
+
assert lock.is_acquired() is False
|
|
409
440
|
|
|
410
441
|
|
|
411
442
|
@pytest.mark.parametrize(
|
|
@@ -417,23 +448,23 @@ def test_is_locked_unexpected_members(
|
|
|
417
448
|
(False, False, False),
|
|
418
449
|
],
|
|
419
450
|
)
|
|
420
|
-
def
|
|
451
|
+
def test_is_acquired_unexpected_methods(
|
|
421
452
|
fmu_dir: ProjectFMUDirectory,
|
|
422
453
|
monkeypatch: MonkeyPatch,
|
|
423
454
|
is_mine: bool,
|
|
424
455
|
is_stale: bool,
|
|
425
456
|
expected: bool,
|
|
426
457
|
) -> None:
|
|
427
|
-
"""Tests
|
|
458
|
+
"""Tests is_acquired under expected method conditions."""
|
|
428
459
|
lock = LockManager(fmu_dir)
|
|
429
|
-
assert lock.
|
|
460
|
+
assert lock.is_acquired() is False
|
|
430
461
|
lock.acquire()
|
|
431
462
|
|
|
432
463
|
with (
|
|
433
464
|
patch.object(lock, "_is_mine", return_value=is_mine),
|
|
434
465
|
patch.object(lock, "_is_stale", return_value=is_stale),
|
|
435
466
|
):
|
|
436
|
-
assert lock.
|
|
467
|
+
assert lock.is_acquired() is expected
|
|
437
468
|
|
|
438
469
|
|
|
439
470
|
def test_refresh_works_as_expected(
|
|
@@ -87,6 +87,62 @@ def test_pydantic_resource_manager_load(fmu_dir: ProjectFMUDirectory) -> None:
|
|
|
87
87
|
assert a._cache == a_model
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def test_pydantic_resource_manager_load_force_true(
|
|
91
|
+
fmu_dir: ProjectFMUDirectory,
|
|
92
|
+
) -> None:
|
|
93
|
+
"""Tests loading a Pydantic resource with force=True."""
|
|
94
|
+
a = AManager(fmu_dir)
|
|
95
|
+
a_model = A(foo="bar")
|
|
96
|
+
a.save(a_model)
|
|
97
|
+
assert a.load() == a_model
|
|
98
|
+
assert a._cache == a_model
|
|
99
|
+
|
|
100
|
+
a_shadow = AManager(fmu_dir)
|
|
101
|
+
a_shadow_model = A(foo="baz")
|
|
102
|
+
a_shadow.save(a_shadow_model)
|
|
103
|
+
|
|
104
|
+
assert a_shadow.load() == a_shadow_model
|
|
105
|
+
assert a_shadow._cache == a_shadow_model
|
|
106
|
+
|
|
107
|
+
assert a.load() == a_model
|
|
108
|
+
assert a._cache == a_model
|
|
109
|
+
|
|
110
|
+
assert a.load(force=True) == a_shadow_model
|
|
111
|
+
assert a._cache == a_shadow_model
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_pydantic_resource_manager_load_cache_false(
|
|
115
|
+
fmu_dir: ProjectFMUDirectory,
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Tests loading a Pydantic resource with cache=False."""
|
|
118
|
+
a = AManager(fmu_dir)
|
|
119
|
+
a_model = A(foo="bar")
|
|
120
|
+
a.save(a_model)
|
|
121
|
+
|
|
122
|
+
a_shadow = AManager(fmu_dir)
|
|
123
|
+
assert a_shadow.load(store_cache=False) == a_model
|
|
124
|
+
assert a_shadow._cache is None
|
|
125
|
+
|
|
126
|
+
assert a_shadow.load(store_cache=True) == a_model
|
|
127
|
+
assert a_shadow._cache == a_model
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_pydantic_resource_manager_load_force_true_cache_false(
|
|
131
|
+
fmu_dir: ProjectFMUDirectory,
|
|
132
|
+
) -> None:
|
|
133
|
+
"""Tests loading a Pydantic resource with force=True, cache=False."""
|
|
134
|
+
a = AManager(fmu_dir)
|
|
135
|
+
a_model = A(foo="bar")
|
|
136
|
+
a.save(a_model)
|
|
137
|
+
|
|
138
|
+
a_shadow = AManager(fmu_dir)
|
|
139
|
+
a_shadow_model = A(foo="baz")
|
|
140
|
+
a_shadow.save(a_shadow_model)
|
|
141
|
+
|
|
142
|
+
assert a.load(force=True, store_cache=False) == a_shadow_model
|
|
143
|
+
assert a._cache is a_model
|
|
144
|
+
|
|
145
|
+
|
|
90
146
|
def test_pydantic_resource_manager_loads_invalid_model(
|
|
91
147
|
fmu_dir: ProjectFMUDirectory,
|
|
92
148
|
) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|