fmu-settings 0.5.1__tar.gz → 0.5.3__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.5.1 → fmu_settings-0.5.3}/PKG-INFO +1 -1
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_resources/lock_manager.py +7 -1
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_resources/pydantic_resource_manager.py +45 -45
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_version.py +3 -3
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu_settings.egg-info/PKG-INFO +1 -1
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/test_resources/test_lock_manager.py +15 -8
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/.coveragerc +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/.github/pull_request_template.md +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/.github/workflows/ci.yml +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/.github/workflows/codeql.yml +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/.github/workflows/publish.yml +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/.gitignore +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/CONTRIBUTING.md +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/LICENSE +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/README.md +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/SECURITY.md +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/pyproject.toml +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/setup.cfg +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/__init__.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/__init__.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_fmu_dir.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_global_config.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_init.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_logging.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_resources/__init__.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_resources/config_managers.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/models/__init__.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/models/_enums.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/models/_mappings.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/models/lock_info.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/models/project_config.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/models/user_config.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/py.typed +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/types.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu_settings.egg-info/SOURCES.txt +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu_settings.egg-info/dependency_links.txt +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu_settings.egg-info/requires.txt +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu_settings.egg-info/top_level.txt +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/conftest.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/test_fmu_dir.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/test_global_config.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/test_init.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/test_resources/test_project_config.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/test_resources/test_resource_managers.py +0 -0
- {fmu_settings-0.5.1 → fmu_settings-0.5.3}/tests/test_resources/test_user_config.py +0 -0
|
@@ -32,6 +32,10 @@ class LockError(Exception):
|
|
|
32
32
|
"""Raised when the lock cannot be acquired."""
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
class LockNotFoundError(FileNotFoundError):
|
|
36
|
+
"""Raised when the lock cannot be found."""
|
|
37
|
+
|
|
38
|
+
|
|
35
39
|
class LockManager(PydanticResourceManager[LockInfo]):
|
|
36
40
|
"""Manages the .lock file."""
|
|
37
41
|
|
|
@@ -194,7 +198,9 @@ class LockManager(PydanticResourceManager[LockInfo]):
|
|
|
194
198
|
LockError: If we don't hold the lock or it's invalid
|
|
195
199
|
"""
|
|
196
200
|
if not self.exists:
|
|
197
|
-
|
|
201
|
+
if self.is_acquired():
|
|
202
|
+
self.release()
|
|
203
|
+
raise LockNotFoundError("Cannot refresh: lock file does not exist")
|
|
198
204
|
|
|
199
205
|
lock_info = self._safe_load()
|
|
200
206
|
if not lock_info or not self._is_mine(lock_info):
|
{fmu_settings-0.5.1 → fmu_settings-0.5.3}/src/fmu/settings/_resources/pydantic_resource_manager.py
RENAMED
|
@@ -112,21 +112,21 @@ class PydanticResourceManager(Generic[PydanticResource]):
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticResource]):
|
|
115
|
-
"""Manages the .fmu
|
|
115
|
+
"""Manages the .fmu resource file."""
|
|
116
116
|
|
|
117
117
|
def __init__(
|
|
118
|
-
self: Self, fmu_dir: FMUDirectoryBase,
|
|
118
|
+
self: Self, fmu_dir: FMUDirectoryBase, resource: type[MutablePydanticResource]
|
|
119
119
|
) -> None:
|
|
120
|
-
"""Initializes the
|
|
121
|
-
super().__init__(fmu_dir,
|
|
120
|
+
"""Initializes the resource manager."""
|
|
121
|
+
super().__init__(fmu_dir, resource)
|
|
122
122
|
|
|
123
123
|
def _get_dot_notation_key(
|
|
124
|
-
self: Self,
|
|
124
|
+
self: Self, resource_dict: dict[str, Any], key: str, default: Any = None
|
|
125
125
|
) -> Any:
|
|
126
126
|
"""Sets the value to a dot-notation key.
|
|
127
127
|
|
|
128
128
|
Args:
|
|
129
|
-
|
|
129
|
+
resource_dict: The resource dictionary we are modifying (by reference)
|
|
130
130
|
key: The key to set
|
|
131
131
|
default: Value to return if key is not found. Default None
|
|
132
132
|
|
|
@@ -134,7 +134,7 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
|
|
|
134
134
|
The value or default
|
|
135
135
|
"""
|
|
136
136
|
parts = key.split(".")
|
|
137
|
-
value =
|
|
137
|
+
value = resource_dict
|
|
138
138
|
for part in parts:
|
|
139
139
|
if isinstance(value, dict) and part in value:
|
|
140
140
|
value = value[part]
|
|
@@ -144,28 +144,28 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
|
|
|
144
144
|
return value
|
|
145
145
|
|
|
146
146
|
def get(self: Self, key: str, default: Any = None) -> Any:
|
|
147
|
-
"""Gets a
|
|
147
|
+
"""Gets a resource value by key.
|
|
148
148
|
|
|
149
149
|
Supports dot notation for nested values (e.g., "foo.bar")
|
|
150
150
|
|
|
151
151
|
Args:
|
|
152
|
-
key: The
|
|
152
|
+
key: The resource key
|
|
153
153
|
default: Value to return if key is not found. Default None
|
|
154
154
|
|
|
155
155
|
Returns:
|
|
156
|
-
The
|
|
156
|
+
The resource value or default
|
|
157
157
|
"""
|
|
158
158
|
try:
|
|
159
|
-
|
|
159
|
+
resource = self.load()
|
|
160
160
|
|
|
161
161
|
if "." in key:
|
|
162
|
-
return self._get_dot_notation_key(
|
|
162
|
+
return self._get_dot_notation_key(resource.model_dump(), key, default)
|
|
163
163
|
|
|
164
|
-
if hasattr(
|
|
165
|
-
return getattr(
|
|
164
|
+
if hasattr(resource, key):
|
|
165
|
+
return getattr(resource, key)
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
return
|
|
167
|
+
resource_dict = resource.model_dump()
|
|
168
|
+
return resource_dict.get(key, default)
|
|
169
169
|
except FileNotFoundError as e:
|
|
170
170
|
raise FileNotFoundError(
|
|
171
171
|
f"Resource file for '{self.__class__.__name__}' not found "
|
|
@@ -173,17 +173,17 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
|
|
|
173
173
|
) from e
|
|
174
174
|
|
|
175
175
|
def _set_dot_notation_key(
|
|
176
|
-
self: Self,
|
|
176
|
+
self: Self, resource_dict: dict[str, Any], key: str, value: Any
|
|
177
177
|
) -> None:
|
|
178
178
|
"""Sets the value to a dot-notation key.
|
|
179
179
|
|
|
180
180
|
Args:
|
|
181
|
-
|
|
181
|
+
resource_dict: The resource dictionary we are modifying (by reference)
|
|
182
182
|
key: The key to set
|
|
183
183
|
value: The value to set
|
|
184
184
|
"""
|
|
185
185
|
parts = key.split(".")
|
|
186
|
-
target =
|
|
186
|
+
target = resource_dict
|
|
187
187
|
|
|
188
188
|
for part in parts[:-1]:
|
|
189
189
|
if part not in target or not isinstance(target[part], dict):
|
|
@@ -193,27 +193,27 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
|
|
|
193
193
|
target[parts[-1]] = value
|
|
194
194
|
|
|
195
195
|
def set(self: Self, key: str, value: Any) -> None:
|
|
196
|
-
"""Sets a
|
|
196
|
+
"""Sets a resource value by key.
|
|
197
197
|
|
|
198
198
|
Args:
|
|
199
|
-
key: The
|
|
199
|
+
key: The resource key
|
|
200
200
|
value: The value to set
|
|
201
201
|
|
|
202
202
|
Raises:
|
|
203
|
-
FileNotFoundError: If
|
|
204
|
-
ValueError: If the updated
|
|
203
|
+
FileNotFoundError: If resource file doesn't exist
|
|
204
|
+
ValueError: If the updated resource is invalid
|
|
205
205
|
"""
|
|
206
206
|
try:
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
resource = self.load()
|
|
208
|
+
resource_dict = resource.model_dump()
|
|
209
209
|
|
|
210
210
|
if "." in key:
|
|
211
|
-
self._set_dot_notation_key(
|
|
211
|
+
self._set_dot_notation_key(resource_dict, key, value)
|
|
212
212
|
else:
|
|
213
|
-
|
|
213
|
+
resource_dict[key] = value
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
self.save(
|
|
215
|
+
updated_resource = resource.model_validate(resource_dict)
|
|
216
|
+
self.save(updated_resource)
|
|
217
217
|
except ValidationError as e:
|
|
218
218
|
raise ValueError(
|
|
219
219
|
f"Invalid value set for '{self.__class__.__name__}' with "
|
|
@@ -226,31 +226,31 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
|
|
|
226
226
|
) from e
|
|
227
227
|
|
|
228
228
|
def update(self: Self, updates: dict[str, Any]) -> MutablePydanticResource:
|
|
229
|
-
"""Updates multiple
|
|
229
|
+
"""Updates multiple resource values at once.
|
|
230
230
|
|
|
231
231
|
Args:
|
|
232
232
|
updates: Dictionary of key-value pairs to update
|
|
233
233
|
|
|
234
234
|
Returns:
|
|
235
|
-
The updated
|
|
235
|
+
The updated Resource object
|
|
236
236
|
|
|
237
237
|
Raises:
|
|
238
|
-
FileNotFoundError: If
|
|
239
|
-
ValueError: If the updates
|
|
238
|
+
FileNotFoundError: If resource file doesn't exist
|
|
239
|
+
ValueError: If the updates resource is invalid
|
|
240
240
|
"""
|
|
241
241
|
try:
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
resource = self.load()
|
|
243
|
+
resource_dict = resource.model_dump()
|
|
244
244
|
|
|
245
245
|
flat_updates = {k: v for k, v in updates.items() if "." not in k}
|
|
246
|
-
|
|
246
|
+
resource_dict.update(flat_updates)
|
|
247
247
|
|
|
248
248
|
for key, value in updates.items():
|
|
249
249
|
if "." in key:
|
|
250
|
-
self._set_dot_notation_key(
|
|
250
|
+
self._set_dot_notation_key(resource_dict, key, value)
|
|
251
251
|
|
|
252
|
-
|
|
253
|
-
self.save(
|
|
252
|
+
updated_resource = resource.model_validate(resource_dict)
|
|
253
|
+
self.save(updated_resource)
|
|
254
254
|
except ValidationError as e:
|
|
255
255
|
raise ValueError(
|
|
256
256
|
f"Invalid value set for '{self.__class__.__name__}' with "
|
|
@@ -262,14 +262,14 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
|
|
|
262
262
|
f"at: '{self.path}' when setting updates {updates}"
|
|
263
263
|
) from e
|
|
264
264
|
|
|
265
|
-
return
|
|
265
|
+
return updated_resource
|
|
266
266
|
|
|
267
267
|
def reset(self: Self) -> MutablePydanticResource:
|
|
268
|
-
"""Resets the
|
|
268
|
+
"""Resets the resources to defaults.
|
|
269
269
|
|
|
270
270
|
Returns:
|
|
271
|
-
The new default
|
|
271
|
+
The new default resource object
|
|
272
272
|
"""
|
|
273
|
-
|
|
274
|
-
self.save(
|
|
275
|
-
return
|
|
273
|
+
resource = self.model_class.reset()
|
|
274
|
+
self.save(resource)
|
|
275
|
+
return resource
|
|
@@ -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.5.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 5,
|
|
31
|
+
__version__ = version = '0.5.3'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 5, 3)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g7953e1c0f'
|
|
@@ -19,6 +19,7 @@ from fmu.settings._resources.lock_manager import (
|
|
|
19
19
|
DEFAULT_LOCK_TIMEOUT,
|
|
20
20
|
LockError,
|
|
21
21
|
LockManager,
|
|
22
|
+
LockNotFoundError,
|
|
22
23
|
)
|
|
23
24
|
from fmu.settings.models.lock_info import LockInfo
|
|
24
25
|
|
|
@@ -493,15 +494,21 @@ def test_refresh_works_as_expected(
|
|
|
493
494
|
def test_refresh_without_lock_file(
|
|
494
495
|
fmu_dir: ProjectFMUDirectory, monkeypatch: MonkeyPatch
|
|
495
496
|
) -> None:
|
|
496
|
-
"""Tests
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
lock.refresh()
|
|
497
|
+
"""Tests that if a user deletes anothers lock it's invalidated on a refresh."""
|
|
498
|
+
with pytest.raises(LockNotFoundError, match="does not exist"):
|
|
499
|
+
fmu_dir._lock.refresh()
|
|
500
500
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
501
|
+
fmu_dir._lock.acquire()
|
|
502
|
+
assert fmu_dir._lock.is_acquired() is True
|
|
503
|
+
|
|
504
|
+
# Someone deletes the lock
|
|
505
|
+
fmu_dir._lock.path.unlink()
|
|
506
|
+
|
|
507
|
+
with pytest.raises(
|
|
508
|
+
LockNotFoundError, match="Cannot refresh: lock file does not exist"
|
|
509
|
+
):
|
|
510
|
+
fmu_dir._lock.refresh()
|
|
511
|
+
assert fmu_dir._lock.is_acquired() is False
|
|
505
512
|
|
|
506
513
|
|
|
507
514
|
def test_refresh_without_owning_lock(
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|