fmu-settings 0.5.2__py3-none-any.whl → 0.14.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.
@@ -2,11 +2,14 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import copy
5
6
  import json
6
- from typing import TYPE_CHECKING, Any, Generic, Self, TypeVar
7
+ from builtins import TypeError
8
+ from typing import TYPE_CHECKING, Any, Final, Generic, Self, TypeVar
7
9
 
8
10
  from pydantic import BaseModel, ValidationError
9
11
 
12
+ from fmu.settings.models.project_config import ProjectConfig
10
13
  from fmu.settings.types import ResettableBaseModel
11
14
 
12
15
  if TYPE_CHECKING:
@@ -22,6 +25,8 @@ MutablePydanticResource = TypeVar("MutablePydanticResource", bound=ResettableBas
22
25
  class PydanticResourceManager(Generic[PydanticResource]):
23
26
  """Base class for managing resources represented by Pydantic models."""
24
27
 
28
+ automatic_caching: bool = True
29
+
25
30
  def __init__(
26
31
  self: Self, fmu_dir: FMUDirectoryBase, model_class: type[PydanticResource]
27
32
  ) -> None:
@@ -53,6 +58,30 @@ class PydanticResourceManager(Generic[PydanticResource]):
53
58
  """Returns whether or not the resource exists."""
54
59
  return self.path.exists()
55
60
 
61
+ @staticmethod
62
+ def _get_dot_notation_key(
63
+ resource_dict: dict[str, Any], key: str, default: Any = None
64
+ ) -> Any:
65
+ """Get a value from the resource by a dot-notation key.
66
+
67
+ Args:
68
+ resource_dict: The resource dictionary to get the value from
69
+ key: The key to the value in the resource
70
+ default: Value to return if key is not found. Default None
71
+
72
+ Returns:
73
+ The value or default
74
+ """
75
+ parts = key.split(".")
76
+ value = resource_dict
77
+ for part in parts:
78
+ if isinstance(value, dict) and part in value:
79
+ value = value[part]
80
+ else:
81
+ return default
82
+
83
+ return value
84
+
56
85
  def load(
57
86
  self: Self, force: bool = False, store_cache: bool = True
58
87
  ) -> PydanticResource:
@@ -99,17 +128,103 @@ class PydanticResourceManager(Generic[PydanticResource]):
99
128
 
100
129
  return self._cache
101
130
 
102
- def save(self: Self, model: PydanticResource) -> None:
131
+ def save(
132
+ self: Self,
133
+ model: PydanticResource,
134
+ ) -> None:
103
135
  """Save the Pydantic model to disk.
104
136
 
105
137
  Args:
106
- model: Validated Pydantic model instance
138
+ model: Validated Pydantic model instance.
107
139
  """
108
140
  self.fmu_dir._lock.ensure_can_write()
141
+
109
142
  json_data = model.model_dump_json(by_alias=True, indent=2)
110
143
  self.fmu_dir.write_text_file(self.relative_path, json_data)
144
+
145
+ if self.automatic_caching and self.exists:
146
+ self.fmu_dir.cache.store_revision(self.relative_path, json_data)
147
+
111
148
  self._cache = model
112
149
 
150
+ @staticmethod
151
+ def get_model_diff(
152
+ current_model: BaseModel, incoming_model: BaseModel, prefix: str = ""
153
+ ) -> list[tuple[str, Any, Any]]:
154
+ """Recursively get differences between two Pydantic models.
155
+
156
+ Returns:
157
+ A list of differences between the models on field level.
158
+ """
159
+ if type(incoming_model) is not type(current_model):
160
+ raise ValueError(
161
+ "Models must be of the same type. Current model is of type "
162
+ f"'{current_model.__class__.__name__}', incoming model of type "
163
+ f"'{incoming_model.__class__.__name__}'."
164
+ )
165
+
166
+ IGNORED_FIELDS: Final[list[str]] = [
167
+ "created_at",
168
+ "created_by",
169
+ "last_modified_at",
170
+ "last_modified_by",
171
+ ]
172
+ changes: list[tuple[str, Any, Any]] = []
173
+
174
+ for field_name in type(current_model).model_fields:
175
+ if field_name in IGNORED_FIELDS:
176
+ continue
177
+
178
+ current_value = getattr(current_model, field_name)
179
+ incoming_value = getattr(incoming_model, field_name)
180
+
181
+ field_path = f"{prefix}.{field_name}" if prefix else field_name
182
+
183
+ if current_value is None and incoming_value is not None:
184
+ changes.append((field_path, None, incoming_value))
185
+ elif current_value is not None and incoming_value is None:
186
+ changes.append((field_path, current_value, None))
187
+ elif isinstance(current_value, BaseModel) and isinstance(
188
+ incoming_value, BaseModel
189
+ ):
190
+ changes.extend(
191
+ PydanticResourceManager.get_model_diff(
192
+ current_value, incoming_value, field_path
193
+ )
194
+ )
195
+ elif isinstance(current_value, list) and isinstance(incoming_value, list):
196
+ if current_value != incoming_value:
197
+ changes.append((field_path, current_value, incoming_value))
198
+ elif current_value != incoming_value:
199
+ changes.append((field_path, current_value, incoming_value))
200
+
201
+ return changes
202
+
203
+ def get_resource_diff(
204
+ self: Self, incoming_resource: PydanticResourceManager[PydanticResource]
205
+ ) -> list[tuple[str, Any, Any]]:
206
+ """Get differences between current and incoming Pydantic resource.
207
+
208
+ Returns:
209
+ A list of differences between the resources.
210
+ """
211
+ if self.exists and incoming_resource.exists:
212
+ current_model = self.load()
213
+ incoming_model = incoming_resource.load()
214
+ if type(current_model) is not type(incoming_model):
215
+ raise TypeError(
216
+ f"Resources to diff must be of the same type. Current resource is "
217
+ f"of type '{self.model_class.__name__}', incoming resource of type "
218
+ f"'{incoming_model.__class__.__name__}'."
219
+ )
220
+ return self.get_model_diff(current_model, incoming_model)
221
+ raise FileNotFoundError(
222
+ "Resources to diff must exist in both directories: "
223
+ f"Current resource {str(self.relative_path)} exists: {self.exists}. "
224
+ f"Incoming resource {str(incoming_resource.relative_path)} exists: "
225
+ f"{incoming_resource.exists}."
226
+ )
227
+
113
228
 
114
229
  class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticResource]):
115
230
  """Manages the .fmu resource file."""
@@ -120,29 +235,6 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
120
235
  """Initializes the resource manager."""
121
236
  super().__init__(fmu_dir, resource)
122
237
 
123
- def _get_dot_notation_key(
124
- self: Self, resource_dict: dict[str, Any], key: str, default: Any = None
125
- ) -> Any:
126
- """Sets the value to a dot-notation key.
127
-
128
- Args:
129
- resource_dict: The resource dictionary we are modifying (by reference)
130
- key: The key to set
131
- default: Value to return if key is not found. Default None
132
-
133
- Returns:
134
- The value or default
135
- """
136
- parts = key.split(".")
137
- value = resource_dict
138
- for part in parts:
139
- if isinstance(value, dict) and part in value:
140
- value = value[part]
141
- else:
142
- return default
143
-
144
- return value
145
-
146
238
  def get(self: Self, key: str, default: Any = None) -> Any:
147
239
  """Gets a resource value by key.
148
240
 
@@ -206,6 +298,7 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
206
298
  try:
207
299
  resource = self.load()
208
300
  resource_dict = resource.model_dump()
301
+ old_resource_dict = copy.deepcopy(resource_dict)
209
302
 
210
303
  if "." in key:
211
304
  self._set_dot_notation_key(resource_dict, key, value)
@@ -214,6 +307,14 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
214
307
 
215
308
  updated_resource = resource.model_validate(resource_dict)
216
309
  self.save(updated_resource)
310
+
311
+ if self.model_class == ProjectConfig:
312
+ self.fmu_dir._changelog.log_update_to_changelog(
313
+ updates={key: value},
314
+ old_resource_dict=old_resource_dict,
315
+ relative_path=self.relative_path,
316
+ )
317
+
217
318
  except ValidationError as e:
218
319
  raise ValueError(
219
320
  f"Invalid value set for '{self.__class__.__name__}' with "
@@ -241,6 +342,7 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
241
342
  try:
242
343
  resource = self.load()
243
344
  resource_dict = resource.model_dump()
345
+ old_resource_dict = copy.deepcopy(resource_dict)
244
346
 
245
347
  flat_updates = {k: v for k, v in updates.items() if "." not in k}
246
348
  resource_dict.update(flat_updates)
@@ -251,6 +353,12 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
251
353
 
252
354
  updated_resource = resource.model_validate(resource_dict)
253
355
  self.save(updated_resource)
356
+
357
+ if self.model_class == ProjectConfig:
358
+ self.fmu_dir._changelog.log_update_to_changelog(
359
+ updates, old_resource_dict, self.relative_path
360
+ )
361
+
254
362
  except ValidationError as e:
255
363
  raise ValueError(
256
364
  f"Invalid value set for '{self.__class__.__name__}' with "
@@ -262,7 +370,7 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
262
370
  f"at: '{self.path}' when setting updates {updates}"
263
371
  ) from e
264
372
 
265
- return updated_resource
373
+ return self.load()
266
374
 
267
375
  def reset(self: Self) -> MutablePydanticResource:
268
376
  """Resets the resources to defaults.
@@ -273,3 +381,41 @@ class MutablePydanticResourceManager(PydanticResourceManager[MutablePydanticReso
273
381
  resource = self.model_class.reset()
274
382
  self.save(resource)
275
383
  return resource
384
+
385
+ def merge_resource(
386
+ self: Self,
387
+ incoming_resource: MutablePydanticResourceManager[MutablePydanticResource],
388
+ ) -> MutablePydanticResource:
389
+ """Merge an incoming Pydantic resource into the current resource model.
390
+
391
+ All changes in the incoming resource will be applied.
392
+
393
+ Returns:
394
+ The updated resource object
395
+ """
396
+ try:
397
+ changes: list[tuple[str, Any, Any]] = self.get_resource_diff(
398
+ incoming_resource
399
+ )
400
+ return self.merge_changes(changes)
401
+ except TypeError as e:
402
+ raise TypeError(
403
+ f"Merging pydantic resource failed. The incoming resource must be of "
404
+ f"type '{self.model_class.__name__}'. The provided model was of type "
405
+ f"'{incoming_resource.model_class.__name__}'."
406
+ ) from e
407
+
408
+ def merge_changes(
409
+ self: Self, changes: list[tuple[str, Any, Any]]
410
+ ) -> MutablePydanticResource:
411
+ """Merge a list of changes into the current resource model.
412
+
413
+ All changes will overwrite the current values.
414
+
415
+ Returns:
416
+ The updated resource object
417
+ """
418
+ updates: dict[str, Any] = {}
419
+ for change in changes:
420
+ updates[change[0]] = change[2]
421
+ return self.update(updates)
@@ -0,0 +1,47 @@
1
+ """Manages an .fmu user_session_log file."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import contextlib
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING, Self
8
+
9
+ from fmu.settings._resources.log_manager import LogManager
10
+ from fmu.settings.models.event_info import EventInfo
11
+ from fmu.settings.models.log import Log, LogFileName
12
+
13
+ if TYPE_CHECKING:
14
+ # Avoid circular dependency for type hint in __init__ only
15
+ from fmu.settings._fmu_dir import (
16
+ FMUDirectoryBase,
17
+ )
18
+
19
+
20
+ class UserSessionLogManager(LogManager[EventInfo]):
21
+ """Manages the .fmu user session log file."""
22
+
23
+ def __init__(
24
+ self: Self, fmu_dir: FMUDirectoryBase, retention_days: int | None = None
25
+ ) -> None:
26
+ """Initializes the User session log resource manager."""
27
+ super().__init__(fmu_dir, Log[EventInfo])
28
+
29
+ # If user_session_log.json exists from previous session, cache it and delete
30
+ # We want a fresh log each time
31
+ if self.exists:
32
+ self.fmu_dir._lock.ensure_can_write()
33
+ content = self.fmu_dir.read_text_file(self.relative_path)
34
+ self.fmu_dir.cache.store_revision(
35
+ self.relative_path, content, skip_trim=True
36
+ )
37
+ with contextlib.suppress(FileNotFoundError):
38
+ self.path.unlink()
39
+
40
+ self.fmu_dir.cache.trim_by_age(
41
+ self.relative_path, retention_days or self.fmu_dir.cache.RETENTION_DAYS
42
+ )
43
+
44
+ @property
45
+ def relative_path(self: Self) -> Path:
46
+ """Returns the relative path to the log file."""
47
+ return Path("logs") / LogFileName.user_session_log
fmu/settings/_version.py CHANGED
@@ -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.2'
32
- __version_tuple__ = version_tuple = (0, 5, 2)
31
+ __version__ = version = '0.14.1'
32
+ __version_tuple__ = version_tuple = (0, 14, 1)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -32,3 +32,21 @@ class DataEntrySource(StrEnum):
32
32
 
33
33
  class TargetSystem(StrEnum):
34
34
  smda = "smda"
35
+
36
+
37
+ class ChangeType(StrEnum):
38
+ """The types of change that can be made on a file."""
39
+
40
+ update = "update"
41
+ remove = "remove"
42
+ add = "add"
43
+ reset = "reset"
44
+ merge = "merge"
45
+
46
+
47
+ class FilterType(StrEnum):
48
+ """The supported types to filter on."""
49
+
50
+ date = "date"
51
+ number = "number"
52
+ text = "text"
@@ -0,0 +1,37 @@
1
+ """Model for the log entries in the the changelog file."""
2
+
3
+ from datetime import UTC, datetime
4
+ from pathlib import Path
5
+
6
+ import pandas as pd
7
+ from pydantic import AwareDatetime, BaseModel, Field, field_validator
8
+
9
+ from fmu.settings.models._enums import ChangeType
10
+
11
+
12
+ class ChangeInfo(BaseModel):
13
+ """Represents a change in the changelog file."""
14
+
15
+ timestamp: AwareDatetime = Field(
16
+ default_factory=lambda: datetime.now(UTC), strict=True
17
+ )
18
+ change_type: ChangeType
19
+ user: str
20
+ path: Path
21
+ change: str
22
+ hostname: str
23
+ file: str
24
+ key: str
25
+
26
+ @field_validator("timestamp", mode="before")
27
+ @classmethod
28
+ def convert_timestamp(cls, value: str) -> AwareDatetime:
29
+ """Convert timestamp values given as a 'str' or Pandas 'Timestamp'.
30
+
31
+ Values of other types will be handled by Pydantic.
32
+ """
33
+ if isinstance(value, str):
34
+ return datetime.fromisoformat(value)
35
+ if isinstance(value, pd.Timestamp):
36
+ return value.to_pydatetime()
37
+ return value
@@ -0,0 +1,15 @@
1
+ """Model for the log entries in the the userlog file."""
2
+
3
+ from datetime import UTC, datetime
4
+
5
+ from pydantic import AwareDatetime, BaseModel, ConfigDict, Field
6
+
7
+
8
+ class EventInfo(BaseModel):
9
+ """Represents information about user session activity."""
10
+
11
+ model_config = ConfigDict(extra="allow")
12
+
13
+ level: str = "INFO"
14
+ event: str = "unknown"
15
+ timestamp: AwareDatetime = Field(default_factory=lambda: datetime.now(UTC))
@@ -0,0 +1,63 @@
1
+ """Module for the log file and related models."""
2
+
3
+ from datetime import datetime
4
+ from enum import StrEnum
5
+ from typing import Any, Literal, Self, TypeVar
6
+
7
+ from pydantic import BaseModel, Field, RootModel
8
+
9
+ from fmu.settings.models._enums import FilterType
10
+
11
+ LogEntryType = TypeVar("LogEntryType", bound=BaseModel)
12
+
13
+
14
+ class Log(RootModel[list[LogEntryType]]):
15
+ """Represents a log file in a .fmu directory."""
16
+
17
+ root: list[LogEntryType] = Field(default_factory=list)
18
+
19
+ def add_entry(self: Self, entry: LogEntryType) -> None:
20
+ """Adds a log entry to the log."""
21
+ self.root.append(entry)
22
+
23
+ def __getitem__(self: Self, index: int) -> LogEntryType:
24
+ """Retrieves a log entry from the log using the specified index."""
25
+ return self.root[index]
26
+
27
+ def __iter__(self: Self) -> Any:
28
+ """Returns an iterator for the log."""
29
+ return iter(self.root)
30
+
31
+ def __len__(self: Self) -> int:
32
+ """Returns the number of log entries in the log."""
33
+ return len(self.root)
34
+
35
+
36
+ class Filter(BaseModel):
37
+ """Represents a filter that can be applied on a log file."""
38
+
39
+ field_name: str
40
+ filter_value: str
41
+ filter_type: FilterType
42
+ operator: Literal[">", ">=", "<", "<=", "==", "!="]
43
+
44
+ def parse_filter_value(self: Self) -> str | datetime | int:
45
+ """Parse filter value to its type."""
46
+ match self.filter_type:
47
+ case FilterType.date:
48
+ return datetime.fromisoformat(self.filter_value)
49
+ case FilterType.number:
50
+ return int(self.filter_value)
51
+ case FilterType.text:
52
+ return self.filter_value
53
+ case _:
54
+ raise ValueError(
55
+ "Invalid filter type supplied when parsing filter value."
56
+ )
57
+
58
+
59
+ class LogFileName(StrEnum):
60
+ """The log files in the .fmu directory."""
61
+
62
+ changelog = "changelog.json"
63
+ user_session_log = "user_session_log.json"
@@ -2,15 +2,61 @@
2
2
 
3
3
  import getpass
4
4
  from datetime import UTC, datetime
5
+ from pathlib import Path
5
6
  from typing import Self
6
7
 
7
- from pydantic import AwareDatetime, Field
8
+ from pydantic import AwareDatetime, BaseModel, Field
8
9
 
9
10
  from fmu.datamodels.fmu_results.fields import Access, Masterdata, Model
10
11
  from fmu.settings import __version__
11
12
  from fmu.settings.types import ResettableBaseModel, VersionStr # noqa: TC001
12
13
 
13
14
 
15
+ class RmsCoordinateSystem(BaseModel):
16
+ """The project coordinate system of an RMS project."""
17
+
18
+ name: str
19
+ """Name of the coordinate system."""
20
+
21
+
22
+ class RmsStratigraphicZone(BaseModel):
23
+ """A stratigraphic zone from an RMS project."""
24
+
25
+ name: str
26
+ """Name of the zone."""
27
+
28
+ top_horizon_name: str
29
+ """Name of the horizon at the top of the zone."""
30
+
31
+ base_horizon_name: str
32
+ """Name of the horizon at the base of the zone."""
33
+
34
+
35
+ class RmsHorizon(BaseModel):
36
+ """A horizon from an RMS project."""
37
+
38
+ name: str
39
+ """Name of the horizon."""
40
+
41
+
42
+ class RmsWell(BaseModel):
43
+ """A well from an RMS project."""
44
+
45
+ name: str
46
+ """Name of the well."""
47
+
48
+
49
+ class RmsProject(BaseModel):
50
+ """RMS project configuration."""
51
+
52
+ path: Path
53
+ version: str
54
+ coordinate_system: RmsCoordinateSystem | None = None
55
+ zones: list[RmsStratigraphicZone] | None = None
56
+ horizons: list[RmsHorizon] | None = None
57
+ wells: list[RmsWell] | None = None
58
+
59
+
14
60
  class ProjectConfig(ResettableBaseModel):
15
61
  """The configuration file in a .fmu directory.
16
62
 
@@ -20,9 +66,13 @@ class ProjectConfig(ResettableBaseModel):
20
66
  version: VersionStr
21
67
  created_at: AwareDatetime
22
68
  created_by: str
23
- masterdata: Masterdata | None = Field(default=None)
24
- model: Model | None = Field(default=None)
25
- access: Access | None = Field(default=None)
69
+ last_modified_at: AwareDatetime | None = None
70
+ last_modified_by: str | None = None
71
+ masterdata: Masterdata | None = None
72
+ model: Model | None = None
73
+ access: Access | None = None
74
+ cache_max_revisions: int = Field(default=5, ge=5)
75
+ rms: RmsProject | None = None
26
76
 
27
77
  @classmethod
28
78
  def reset(cls: type[Self]) -> Self:
@@ -35,7 +85,11 @@ class ProjectConfig(ResettableBaseModel):
35
85
  version=__version__,
36
86
  created_at=datetime.now(UTC),
37
87
  created_by=getpass.getuser(),
88
+ last_modified_at=None,
89
+ last_modified_by=None,
38
90
  masterdata=None,
39
91
  model=None,
40
92
  access=None,
93
+ cache_max_revisions=5,
94
+ rms=None,
41
95
  )
@@ -10,6 +10,7 @@ import annotated_types
10
10
  from pydantic import (
11
11
  AwareDatetime,
12
12
  BaseModel,
13
+ Field,
13
14
  SecretStr,
14
15
  field_serializer,
15
16
  field_validator,
@@ -42,6 +43,8 @@ class UserConfig(ResettableBaseModel):
42
43
 
43
44
  version: VersionStr
44
45
  created_at: AwareDatetime
46
+ last_modified_at: AwareDatetime | None = None
47
+ cache_max_revisions: int = Field(default=5, ge=5)
45
48
  user_api_keys: UserAPIKeys
46
49
  recent_project_directories: RecentProjectDirectories
47
50
 
@@ -51,6 +54,8 @@ class UserConfig(ResettableBaseModel):
51
54
  return cls(
52
55
  version=__version__,
53
56
  created_at=datetime.now(UTC),
57
+ last_modified_at=None,
58
+ cache_max_revisions=5,
54
59
  user_api_keys=UserAPIKeys(),
55
60
  recent_project_directories=[],
56
61
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu-settings
3
- Version: 0.5.2
3
+ Version: 0.14.1
4
4
  Summary: A library for managing FMU settings
5
5
  Author-email: Equinor <fg-fmu_atlas@equinor.com>
6
6
  License: GPL-3.0
@@ -21,9 +21,11 @@ Requires-Dist: PyYAML
21
21
  Requires-Dist: annotated_types
22
22
  Requires-Dist: fmu-config
23
23
  Requires-Dist: fmu-datamodels
24
+ Requires-Dist: pandas
24
25
  Requires-Dist: pydantic
25
26
  Provides-Extra: dev
26
27
  Requires-Dist: mypy; extra == "dev"
28
+ Requires-Dist: pandas-stubs; extra == "dev"
27
29
  Requires-Dist: pytest; extra == "dev"
28
30
  Requires-Dist: pytest-cov; extra == "dev"
29
31
  Requires-Dist: pytest-mock; extra == "dev"
@@ -0,0 +1,32 @@
1
+ fmu/__init__.py,sha256=htx6HlMme77I6pZ8U256-2B2cMJuELsu3JN3YM2Efh4,144
2
+ fmu/settings/__init__.py,sha256=CkEE7al_uBCQO1lxBKN5LzyCwzzH5Aq6kkEIR7f-zTw,336
3
+ fmu/settings/_fmu_dir.py,sha256=lmGliopDfB2QiWWAowzuaTGcN_nCYzb58-4woBAi-2g,19769
4
+ fmu/settings/_global_config.py,sha256=C0_o99OhOc49ynz4h6ygbbHHH8OOI5lcVFr-9FCwD0c,9331
5
+ fmu/settings/_init.py,sha256=rgt5aZou54RiVAOegC4kzoigJcZefPY4Kv6ke7OAIxI,4014
6
+ fmu/settings/_logging.py,sha256=nEdmZlNCBsB1GfDmFMKCjZmeuRp3CRlbz1EYUemc95Y,1104
7
+ fmu/settings/_readme_texts.py,sha256=0N3Tn3sUKc3PdTiaWzfe7fu7aAphdwMvlG_4ag3h3UE,1067
8
+ fmu/settings/_version.py,sha256=a3VJZDtDsD7dO22j4y92zbdkUlJwzXf_QabiVquJm1Y,706
9
+ fmu/settings/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ fmu/settings/types.py,sha256=aeXEsznBTT1YRRY_LSRqK1j2gmMmyLYYTGYl3a9fweU,513
11
+ fmu/settings/_resources/__init__.py,sha256=LHYR_F7lNGdv8N6R3cEwds5CJQpkOthXFqsEs24vgF8,118
12
+ fmu/settings/_resources/cache_manager.py,sha256=QxmIM0jJRgJsmD_69juPRnUmGrRJ6ZbFp6wc-KW7baA,7192
13
+ fmu/settings/_resources/changelog_manager.py,sha256=ubb7gqWKlAzuh3WyWSRXFFjl8Kso4amTKJPLNf4t6Mw,5857
14
+ fmu/settings/_resources/config_managers.py,sha256=HULkmmxKHN0_aDkPd3DrLaWv2X-njBBCQwXU-H55jdw,2334
15
+ fmu/settings/_resources/lock_manager.py,sha256=tqDqMhovED52a8vEcoJCbfJqgKAk2lsp5eUOtZteU00,10512
16
+ fmu/settings/_resources/log_manager.py,sha256=Ru7dLE6Ugnz0NYORf29kZdkrg3scV7v7z8xDiKP7wEI,3736
17
+ fmu/settings/_resources/pydantic_resource_manager.py,sha256=F2XDWx4RQktJSKC247J2EtJvsmT_DzZGJ9oE2Tt63Zs,14927
18
+ fmu/settings/_resources/user_session_log_manager.py,sha256=aGbOkjyvqKPTdKyhtNUmuWIWyRqsXIcVrNTgmq8e2yc,1610
19
+ fmu/settings/models/__init__.py,sha256=lRlXgl55ba2upmDzdvzx8N30JMq2Osnm8aa_xxTZn8A,112
20
+ fmu/settings/models/_enums.py,sha256=sBvn-2sYVToK7WBMR6PGHtdkh1MwDB0d1_6oWJMIvII,1054
21
+ fmu/settings/models/_mappings.py,sha256=Z4Ex7MtmajBr6FjaNzmwDRwtJlaZZ8YKh9NDmZHRKPI,2832
22
+ fmu/settings/models/change_info.py,sha256=5X8wIItSt_xQ3AQF8EB5moxgIDC_ZyO6Hqkxhdj9l5c,1038
23
+ fmu/settings/models/event_info.py,sha256=7AVDT7QEBHgKTUOHw4ofltQAY9yiYD6aYY8ilO55_9Q,429
24
+ fmu/settings/models/lock_info.py,sha256=-oHDF9v9bDLCoFvEg4S6XXYLeo19zRAZ8HynCv75VWg,711
25
+ fmu/settings/models/log.py,sha256=aP5lQTnKBIiyiTmiMXig0TEpA2yhKz6VOsymaP6EOYk,1943
26
+ fmu/settings/models/project_config.py,sha256=68aEugx7uwkDvVT2vAoS7F6ez8R91cvU0ULf3hwS-rE,2371
27
+ fmu/settings/models/user_config.py,sha256=XYxGhvdIPkQeMWBOwZKekvC-2ldwT1OhrGh9piBxVgk,2851
28
+ fmu_settings-0.14.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
29
+ fmu_settings-0.14.1.dist-info/METADATA,sha256=Zbdj0rdx5SNw1qGME_Gkdvk_wMvFUJFUyoWgHFhbRgw,2183
30
+ fmu_settings-0.14.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ fmu_settings-0.14.1.dist-info/top_level.txt,sha256=Z-FIY3pxn0UK2Wxi9IJ7fKoLSraaxuNGi1eokiE0ShM,4
32
+ fmu_settings-0.14.1.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- fmu/__init__.py,sha256=htx6HlMme77I6pZ8U256-2B2cMJuELsu3JN3YM2Efh4,144
2
- fmu/settings/__init__.py,sha256=CkEE7al_uBCQO1lxBKN5LzyCwzzH5Aq6kkEIR7f-zTw,336
3
- fmu/settings/_fmu_dir.py,sha256=XeZjec78q0IUOpBq-VMkKoWtzXwBeQi2qWRIh_SIFwU,10859
4
- fmu/settings/_global_config.py,sha256=C0_o99OhOc49ynz4h6ygbbHHH8OOI5lcVFr-9FCwD0c,9331
5
- fmu/settings/_init.py,sha256=ucueS0BlEsM3MkX7IaRISloH4vF7-_ZKSphrORbHgJ4,4381
6
- fmu/settings/_logging.py,sha256=nEdmZlNCBsB1GfDmFMKCjZmeuRp3CRlbz1EYUemc95Y,1104
7
- fmu/settings/_version.py,sha256=LGYtjQ6cyPZC_N0AovMIeSYYDK21050nm3HYgDanQBM,704
8
- fmu/settings/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- fmu/settings/types.py,sha256=aeXEsznBTT1YRRY_LSRqK1j2gmMmyLYYTGYl3a9fweU,513
10
- fmu/settings/_resources/__init__.py,sha256=LHYR_F7lNGdv8N6R3cEwds5CJQpkOthXFqsEs24vgF8,118
11
- fmu/settings/_resources/config_managers.py,sha256=QcCLlSw8KdJKrkhGax5teFJzjgQG3ym7Ljs1DykjFbc,1570
12
- fmu/settings/_resources/lock_manager.py,sha256=ekGE5mTcjEWRyoBSIeqaX1r53-WStpYeJYepkOPYi3Q,10061
13
- fmu/settings/_resources/pydantic_resource_manager.py,sha256=BUWO6IHSoT0Ma6QgseweEf7uiGeMwHBEoCyGYPYYFdA,9290
14
- fmu/settings/models/__init__.py,sha256=lRlXgl55ba2upmDzdvzx8N30JMq2Osnm8aa_xxTZn8A,112
15
- fmu/settings/models/_enums.py,sha256=SQUZ-2mQcTx4F0oefPFfuQzMKsKTSFSB-wq_CH7TBRE,734
16
- fmu/settings/models/_mappings.py,sha256=Z4Ex7MtmajBr6FjaNzmwDRwtJlaZZ8YKh9NDmZHRKPI,2832
17
- fmu/settings/models/lock_info.py,sha256=-oHDF9v9bDLCoFvEg4S6XXYLeo19zRAZ8HynCv75VWg,711
18
- fmu/settings/models/project_config.py,sha256=pxb54JmpXNMVAFUu_yJ89dNrYEk6hrPuFfFUpf84Jh0,1099
19
- fmu/settings/models/user_config.py,sha256=dWFTcZY6UnEgNTuGqB-izraJ657PecsW0e0Nt9GBDhI,2666
20
- fmu_settings-0.5.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
21
- fmu_settings-0.5.2.dist-info/METADATA,sha256=dxi2pe4SgYJwTY6beiEPoLx7lEqjzZWq9UcpX3gir_s,2116
22
- fmu_settings-0.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- fmu_settings-0.5.2.dist-info/top_level.txt,sha256=Z-FIY3pxn0UK2Wxi9IJ7fKoLSraaxuNGi1eokiE0ShM,4
24
- fmu_settings-0.5.2.dist-info/RECORD,,