lsst-pex-config 30.0.0rc2__tar.gz → 30.0.0rc3__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.
- {lsst_pex_config-30.0.0rc2/python/lsst_pex_config.egg-info → lsst_pex_config-30.0.0rc3}/PKG-INFO +4 -3
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/CHANGES.rst +23 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/pyproject.toml +3 -2
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/config.py +104 -12
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configChoiceField.py +1 -1
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configDictField.py +1 -1
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/version.py +1 -1
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3/python/lsst_pex_config.egg-info}/PKG-INFO +4 -3
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst_pex_config.egg-info/requires.txt +1 -0
- lsst_pex_config-30.0.0rc3/tests/test__file__.py +103 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_configChoiceField.py +14 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_configDictField.py +13 -0
- lsst_pex_config-30.0.0rc2/tests/test__file__.py +0 -55
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/COPYRIGHT +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/LICENSE +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/MANIFEST.in +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/README.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/bsd_license.txt +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/design-notes.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/field-types.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/index.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/inspecting-configs.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/overview.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/registry-intro.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/wrapping-cpp-control-objects.rst +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/gpl-v3.0.txt +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/__init__.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/__init__.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/__init__.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/_doNotImportMe.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/callStack.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/choiceField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/comparison.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configurableActions/__init__.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configurableActions/_configurableAction.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configurableActions/_configurableActionField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configurableActions/_configurableActionStructField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configurableActions/tests.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configurableField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/convert.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/dictField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/history.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/listField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/py.typed +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/rangeField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/registry.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/wrap.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst_pex_config.egg-info/SOURCES.txt +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst_pex_config.egg-info/dependency_links.txt +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst_pex_config.egg-info/top_level.txt +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst_pex_config.egg-info/zip-safe +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/setup.cfg +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/testLib.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_Config.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_configurableActions.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_configurableField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_dictField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_history.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_listField.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_registry.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_ticket1911.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_ticket1914.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_ticket1915.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_ticket1929.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_ticket1995.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_ticket2818.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_ticketDM-7337.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_unloaded_yaml.py +0 -0
- {lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/tests/test_wrap.py +0 -0
{lsst_pex_config-30.0.0rc2/python/lsst_pex_config.egg-info → lsst_pex_config-30.0.0rc3}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-pex-config
|
|
3
|
-
Version: 30.0.
|
|
3
|
+
Version: 30.0.0rc3
|
|
4
4
|
Summary: A flexible configuration system using Python files.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
6
|
License-Expression: BSD-3-Clause OR GPL-3.0-or-later
|
|
@@ -9,12 +9,12 @@ Keywords: lsst
|
|
|
9
9
|
Classifier: Intended Audience :: Science/Research
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
16
|
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
17
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.11.0
|
|
18
18
|
Description-Content-Type: text/x-rst
|
|
19
19
|
License-File: COPYRIGHT
|
|
20
20
|
License-File: LICENSE
|
|
@@ -22,6 +22,7 @@ License-File: gpl-v3.0.txt
|
|
|
22
22
|
License-File: bsd_license.txt
|
|
23
23
|
Requires-Dist: pyyaml>=5.1
|
|
24
24
|
Requires-Dist: numpy>=1.17
|
|
25
|
+
Requires-Dist: lsst-resources
|
|
25
26
|
Provides-Extra: test
|
|
26
27
|
Requires-Dist: pytest>=3.2; extra == "test"
|
|
27
28
|
Requires-Dist: pytest-openfiles>=0.5.0; extra == "test"
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
lsst-pex-config v30.0.0 (2026-01-15)
|
|
2
|
+
====================================
|
|
3
|
+
|
|
4
|
+
Python 3.11 is now the minimum supported version.
|
|
5
|
+
Tested on Python 3.14.
|
|
6
|
+
|
|
7
|
+
New Features
|
|
8
|
+
------------
|
|
9
|
+
|
|
10
|
+
- Added a ``copy`` method that unfreezes. (`DM-16523 <https://rubinobs.atlassian.net/browse/DM-16523>`_)
|
|
11
|
+
- * Changed the config loader method such that if a relative path is specified inside another config it is treated as being relative to that original config file.
|
|
12
|
+
* Modified the config loader to support URI schemes ``file``, ``resource``, and ``eups`` supported by ``lsst-resources``.
|
|
13
|
+
This change means that in some cases ``__file__`` can be a URI string and not a simple path. (`DM-33226 <https://rubinobs.atlassian.net/browse/DM-33226>`_)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
Bug Fixes
|
|
17
|
+
---------
|
|
18
|
+
|
|
19
|
+
- Fixed a bug that caused history-printing to fail when the initial value for a field was `None`. (`DM-51850 <https://rubinobs.atlassian.net/browse/DM-51850>`_)
|
|
20
|
+
- Fixed copying of ``ConfigDictField``. (`DM-53767 <https://rubinobs.atlassian.net/browse/DM-53767>`_)
|
|
21
|
+
- Fixed copying of ``ConfigChoiceField`` and ``RegistryField``. (`DM-53791 <https://rubinobs.atlassian.net/browse/DM-53791>`_)
|
|
22
|
+
|
|
23
|
+
|
|
1
24
|
lsst-pex-config v29.0.0 (2025-03-25)
|
|
2
25
|
====================================
|
|
3
26
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "lsst-pex-config"
|
|
7
|
-
requires-python = ">=3.
|
|
7
|
+
requires-python = ">=3.11.0"
|
|
8
8
|
description = "A flexible configuration system using Python files."
|
|
9
9
|
license = "BSD-3-Clause OR GPL-3.0-or-later"
|
|
10
10
|
license-files = ["COPYRIGHT", "LICENSE", "gpl-v3.0.txt", "bsd_license.txt"]
|
|
@@ -16,7 +16,7 @@ classifiers = [
|
|
|
16
16
|
"Intended Audience :: Science/Research",
|
|
17
17
|
"Operating System :: OS Independent",
|
|
18
18
|
"Programming Language :: Python :: 3",
|
|
19
|
-
"Programming Language :: Python :: 3.
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
20
|
"Programming Language :: Python :: 3.11",
|
|
21
21
|
"Programming Language :: Python :: 3.12",
|
|
22
22
|
"Programming Language :: Python :: 3.13",
|
|
@@ -26,6 +26,7 @@ keywords = ["lsst"]
|
|
|
26
26
|
dependencies = [
|
|
27
27
|
"pyyaml >=5.1",
|
|
28
28
|
"numpy >= 1.17",
|
|
29
|
+
"lsst-resources",
|
|
29
30
|
]
|
|
30
31
|
dynamic = ["version"]
|
|
31
32
|
|
|
@@ -38,6 +38,7 @@ __all__ = (
|
|
|
38
38
|
import copy
|
|
39
39
|
import importlib
|
|
40
40
|
import io
|
|
41
|
+
import logging
|
|
41
42
|
import math
|
|
42
43
|
import numbers
|
|
43
44
|
import os
|
|
@@ -47,9 +48,13 @@ import sys
|
|
|
47
48
|
import tempfile
|
|
48
49
|
import warnings
|
|
49
50
|
from collections.abc import Mapping
|
|
51
|
+
from contextlib import contextmanager
|
|
52
|
+
from contextvars import ContextVar
|
|
50
53
|
from types import GenericAlias
|
|
51
54
|
from typing import Any, ForwardRef, Generic, TypeVar, cast, overload
|
|
52
55
|
|
|
56
|
+
from lsst.resources import ResourcePath, ResourcePathExpression
|
|
57
|
+
|
|
53
58
|
# if YAML is not available that's fine and we simply don't register
|
|
54
59
|
# the yaml representer since we know it won't be used.
|
|
55
60
|
try:
|
|
@@ -74,6 +79,25 @@ else:
|
|
|
74
79
|
YamlLoaders = ()
|
|
75
80
|
doImport = None
|
|
76
81
|
|
|
82
|
+
_LOG = logging.getLogger(__name__)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# Tracks the current config directory for the current context.
|
|
86
|
+
_config_dir_stack: ContextVar[ResourcePath | None] = ContextVar("_config_dir_stack", default=None)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _get_config_root() -> ResourcePath | None:
|
|
90
|
+
return _config_dir_stack.get()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@contextmanager
|
|
94
|
+
def _push_config_root(dirname: ResourcePath):
|
|
95
|
+
token = _config_dir_stack.set(dirname)
|
|
96
|
+
try:
|
|
97
|
+
yield
|
|
98
|
+
finally:
|
|
99
|
+
_config_dir_stack.reset(token)
|
|
100
|
+
|
|
77
101
|
|
|
78
102
|
class _PexConfigGenericAlias(GenericAlias):
|
|
79
103
|
"""A Subclass of python's GenericAlias used in defining and instantiating
|
|
@@ -1171,15 +1195,51 @@ class Config(metaclass=ConfigMeta): # type: ignore
|
|
|
1171
1195
|
e.add_note(f"No field of name {name} exists in config type {_typeStr(self)}")
|
|
1172
1196
|
raise
|
|
1173
1197
|
|
|
1198
|
+
def _filename_to_resource(
|
|
1199
|
+
self, filename: ResourcePathExpression | None = None
|
|
1200
|
+
) -> tuple[ResourcePath | None, str]:
|
|
1201
|
+
"""Create resource path from filename.
|
|
1202
|
+
|
|
1203
|
+
Parameters
|
|
1204
|
+
----------
|
|
1205
|
+
filename : `lsst.resources.ResourcePathExpression` or `None`
|
|
1206
|
+
The URI expression associated with this config. Can be `None`
|
|
1207
|
+
if no file URI is known.
|
|
1208
|
+
|
|
1209
|
+
Returns
|
|
1210
|
+
-------
|
|
1211
|
+
resource : `lsst.resources.ResourcePath` or `None`
|
|
1212
|
+
The resource version of the filename. Returns `None` if no filename
|
|
1213
|
+
was given or refers to unspecified value.
|
|
1214
|
+
file_string : `str`
|
|
1215
|
+
String form of the resource for use in ``__file__``
|
|
1216
|
+
"""
|
|
1217
|
+
if filename is None or filename in ("?", "<unknown>"):
|
|
1218
|
+
return None, "<unknown>"
|
|
1219
|
+
base = _get_config_root()
|
|
1220
|
+
resource = ResourcePath(filename, forceAbsolute=True, forceDirectory=False, root=base)
|
|
1221
|
+
|
|
1222
|
+
# Preferred definition of __file__ is the full OS path. If a config
|
|
1223
|
+
# is loaded with a relative path it must be converted to the absolute
|
|
1224
|
+
# path to avoid confusion with later relative paths referenced inside
|
|
1225
|
+
# the config.
|
|
1226
|
+
if resource.scheme == "file":
|
|
1227
|
+
file_string = resource.ospath
|
|
1228
|
+
else:
|
|
1229
|
+
file_string = str(resource)
|
|
1230
|
+
|
|
1231
|
+
return resource, file_string
|
|
1232
|
+
|
|
1174
1233
|
def load(self, filename, root="config"):
|
|
1175
1234
|
"""Modify this config in place by executing the Python code in a
|
|
1176
1235
|
configuration file.
|
|
1177
1236
|
|
|
1178
1237
|
Parameters
|
|
1179
1238
|
----------
|
|
1180
|
-
filename : `
|
|
1181
|
-
Name of the configuration
|
|
1182
|
-
module.
|
|
1239
|
+
filename : `lsst.resources.ResourcePathExpression`
|
|
1240
|
+
Name of the configuration URI. A configuration file is a Python
|
|
1241
|
+
module. Since configuration files are Python code, remote URIs
|
|
1242
|
+
are not allowed.
|
|
1183
1243
|
root : `str`, optional
|
|
1184
1244
|
Name of the variable in file that refers to the config being
|
|
1185
1245
|
overridden.
|
|
@@ -1199,9 +1259,21 @@ class Config(metaclass=ConfigMeta): # type: ignore
|
|
|
1199
1259
|
lsst.pex.config.Config.saveToStream
|
|
1200
1260
|
lsst.pex.config.Config.saveToString
|
|
1201
1261
|
"""
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1262
|
+
resource, file_string = self._filename_to_resource(filename)
|
|
1263
|
+
if resource is None:
|
|
1264
|
+
# A filename is required.
|
|
1265
|
+
raise ValueError(f"Undefined URI provided to load command: {filename}.")
|
|
1266
|
+
|
|
1267
|
+
if resource.scheme not in ("file", "eups", "resource"):
|
|
1268
|
+
raise ValueError(f"Remote URI ({resource}) can not be used to load configurations.")
|
|
1269
|
+
|
|
1270
|
+
# Push the directory of the file we are now reading onto the stack
|
|
1271
|
+
# so that nested loads are relative to this file.
|
|
1272
|
+
with _push_config_root(resource.dirname()):
|
|
1273
|
+
_LOG.debug("Updating config from URI %s", str(resource))
|
|
1274
|
+
with resource.open("r") as f:
|
|
1275
|
+
code = compile(f.read(), filename=file_string, mode="exec")
|
|
1276
|
+
self._loadFromString(code, root=root, filename=file_string)
|
|
1205
1277
|
|
|
1206
1278
|
def loadFromStream(self, stream, root="config", filename=None, extraLocals=None):
|
|
1207
1279
|
"""Modify this Config in place by executing the Python code in the
|
|
@@ -1224,7 +1296,8 @@ class Config(metaclass=ConfigMeta): # type: ignore
|
|
|
1224
1296
|
Then this config's field ``myField`` is set to ``5``.
|
|
1225
1297
|
filename : `str`, optional
|
|
1226
1298
|
Name of the configuration file, or `None` if unknown or contained
|
|
1227
|
-
in the stream. Used for error reporting
|
|
1299
|
+
in the stream. Used for error reporting and to set ``__file__``
|
|
1300
|
+
variable in config.
|
|
1228
1301
|
extraLocals : `dict` of `str` to `object`, optional
|
|
1229
1302
|
Any extra variables to include in local scope when loading.
|
|
1230
1303
|
|
|
@@ -1244,7 +1317,7 @@ class Config(metaclass=ConfigMeta): # type: ignore
|
|
|
1244
1317
|
"""
|
|
1245
1318
|
if hasattr(stream, "read"):
|
|
1246
1319
|
if filename is None:
|
|
1247
|
-
filename = getattr(stream, "name", "
|
|
1320
|
+
filename = getattr(stream, "name", "<unknown>")
|
|
1248
1321
|
code = compile(stream.read(), filename=filename, mode="exec")
|
|
1249
1322
|
else:
|
|
1250
1323
|
code = stream
|
|
@@ -1268,9 +1341,11 @@ class Config(metaclass=ConfigMeta): # type: ignore
|
|
|
1268
1341
|
config.myField = 5
|
|
1269
1342
|
|
|
1270
1343
|
Then this config's field ``myField`` is set to ``5``.
|
|
1271
|
-
filename : `
|
|
1272
|
-
|
|
1273
|
-
in the stream. Used for error reporting
|
|
1344
|
+
filename : `lsst.resources.ResourcePathExpression`, optional
|
|
1345
|
+
URI of the configuration file, or `None` if unknown or contained
|
|
1346
|
+
in the stream. Used for error reporting and to set ``__file__``
|
|
1347
|
+
variable. Required to be set if the string config attempts to
|
|
1348
|
+
load other configs using either relative path or ``__file__``.
|
|
1274
1349
|
extraLocals : `dict` of `str` to `object`, optional
|
|
1275
1350
|
Any extra variables to include in local scope when loading.
|
|
1276
1351
|
|
|
@@ -1291,7 +1366,24 @@ class Config(metaclass=ConfigMeta): # type: ignore
|
|
|
1291
1366
|
if filename is None:
|
|
1292
1367
|
# try to determine the file name; a compiled string
|
|
1293
1368
|
# has attribute "co_filename",
|
|
1294
|
-
filename = getattr(code, "co_filename", "
|
|
1369
|
+
filename = getattr(code, "co_filename", "<unknown>")
|
|
1370
|
+
|
|
1371
|
+
resource, file_string = self._filename_to_resource(filename)
|
|
1372
|
+
if resource is None:
|
|
1373
|
+
# No idea where this config came from so no ability to deal with
|
|
1374
|
+
# relative paths. No reason to use context.
|
|
1375
|
+
self._loadFromString(code, root=root, filename=filename, extraLocals=extraLocals)
|
|
1376
|
+
else:
|
|
1377
|
+
# Push the directory of the file we are now reading onto the stack
|
|
1378
|
+
# so that nested loads are relative to this file.
|
|
1379
|
+
with _push_config_root(resource.dirname()):
|
|
1380
|
+
self._loadFromString(code, root=root, filename=file_string, extraLocals=extraLocals)
|
|
1381
|
+
|
|
1382
|
+
def _loadFromString(self, code, root="config", filename=None, extraLocals=None):
|
|
1383
|
+
"""Update config from string.
|
|
1384
|
+
|
|
1385
|
+
Assumes relative directory path context has been setup by caller.
|
|
1386
|
+
"""
|
|
1295
1387
|
with RecordingImporter() as importer:
|
|
1296
1388
|
globals = {"__file__": filename}
|
|
1297
1389
|
local = {root: self}
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configChoiceField.py
RENAMED
|
@@ -192,7 +192,7 @@ class ConfigInstanceDict(collections.abc.Mapping[str, Config]):
|
|
|
192
192
|
result._typemap = self._typemap
|
|
193
193
|
if self._selection is not None:
|
|
194
194
|
if self._field.multi:
|
|
195
|
-
result._selection = SelectionSet(
|
|
195
|
+
result._selection = SelectionSet(self, self._selection._set)
|
|
196
196
|
else:
|
|
197
197
|
result._selection = self._selection
|
|
198
198
|
return result
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "30.0.
|
|
2
|
+
__version__ = "30.0.0rc3"
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3/python/lsst_pex_config.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-pex-config
|
|
3
|
-
Version: 30.0.
|
|
3
|
+
Version: 30.0.0rc3
|
|
4
4
|
Summary: A flexible configuration system using Python files.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
6
|
License-Expression: BSD-3-Clause OR GPL-3.0-or-later
|
|
@@ -9,12 +9,12 @@ Keywords: lsst
|
|
|
9
9
|
Classifier: Intended Audience :: Science/Research
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
16
|
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
17
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.11.0
|
|
18
18
|
Description-Content-Type: text/x-rst
|
|
19
19
|
License-File: COPYRIGHT
|
|
20
20
|
License-File: LICENSE
|
|
@@ -22,6 +22,7 @@ License-File: gpl-v3.0.txt
|
|
|
22
22
|
License-File: bsd_license.txt
|
|
23
23
|
Requires-Dist: pyyaml>=5.1
|
|
24
24
|
Requires-Dist: numpy>=1.17
|
|
25
|
+
Requires-Dist: lsst-resources
|
|
25
26
|
Provides-Extra: test
|
|
26
27
|
Requires-Dist: pytest>=3.2; extra == "test"
|
|
27
28
|
Requires-Dist: pytest-openfiles>=0.5.0; extra == "test"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# This file is part of pex_config.
|
|
2
|
+
#
|
|
3
|
+
# Developed for the LSST Data Management System.
|
|
4
|
+
# This product includes software developed by the LSST Project
|
|
5
|
+
# (http://www.lsst.org).
|
|
6
|
+
# See the COPYRIGHT file at the top-level directory of this distribution
|
|
7
|
+
# for details of code ownership.
|
|
8
|
+
#
|
|
9
|
+
# This software is dual licensed under the GNU General Public License and also
|
|
10
|
+
# under a 3-clause BSD license. Recipients may choose which of these licenses
|
|
11
|
+
# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
|
|
12
|
+
# respectively. If you choose the GPL option then the following text applies
|
|
13
|
+
# (but note that there is still no warranty even if you opt for BSD instead):
|
|
14
|
+
#
|
|
15
|
+
# This program is free software: you can redistribute it and/or modify
|
|
16
|
+
# it under the terms of the GNU General Public License as published by
|
|
17
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
18
|
+
# (at your option) any later version.
|
|
19
|
+
#
|
|
20
|
+
# This program is distributed in the hope that it will be useful,
|
|
21
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
22
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
23
|
+
# GNU General Public License for more details.
|
|
24
|
+
#
|
|
25
|
+
# You should have received a copy of the GNU General Public License
|
|
26
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
27
|
+
|
|
28
|
+
import os
|
|
29
|
+
import unittest
|
|
30
|
+
|
|
31
|
+
import lsst.pex.config as pexConf
|
|
32
|
+
from lsst.resources import ResourcePath
|
|
33
|
+
|
|
34
|
+
TESTDIR = os.path.dirname(os.path.abspath(__file__))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class FileConfig(pexConf.Config):
|
|
38
|
+
"""Config used for testing __file__."""
|
|
39
|
+
|
|
40
|
+
number = pexConf.Field("FileConfig.number", int, default=0)
|
|
41
|
+
filename = pexConf.Field("FileConfig.filename", str, default=None)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class FilenameTestCase(unittest.TestCase):
|
|
45
|
+
"""Check that __file__ can be used in a config file."""
|
|
46
|
+
|
|
47
|
+
def test__file(self):
|
|
48
|
+
fileUri = ResourcePath(f"{TESTDIR}/config/filename.py", forceAbsolute=True, forceDirectory=False)
|
|
49
|
+
for confFile in (os.path.join(TESTDIR, "config", "filename.py"), fileUri, str(fileUri)):
|
|
50
|
+
c = FileConfig()
|
|
51
|
+
c.load(confFile)
|
|
52
|
+
# The __file__ is always the ospath form.
|
|
53
|
+
self.assertEqual(c.filename, os.path.join(TESTDIR, "config", "filename.py"))
|
|
54
|
+
self.assertEqual(c.number, 5)
|
|
55
|
+
|
|
56
|
+
c = FileConfig()
|
|
57
|
+
with fileUri.open("r") as fh:
|
|
58
|
+
c.loadFromStream(fh)
|
|
59
|
+
self.assertEqual(c.filename, os.path.join(TESTDIR, "config", "filename.py"))
|
|
60
|
+
self.assertEqual(c.number, 5)
|
|
61
|
+
|
|
62
|
+
c = FileConfig()
|
|
63
|
+
data = fileUri.read()
|
|
64
|
+
c.loadFromString(data)
|
|
65
|
+
self.assertEqual(c.filename, "<unknown>")
|
|
66
|
+
|
|
67
|
+
c.loadFromString(data, filename=fileUri.ospath)
|
|
68
|
+
self.assertEqual(c.filename, fileUri.ospath)
|
|
69
|
+
|
|
70
|
+
c = FileConfig()
|
|
71
|
+
with self.assertRaises(ValueError):
|
|
72
|
+
# Use mem scheme because we do not support it for config
|
|
73
|
+
# loading and it does not require additional dependencies
|
|
74
|
+
# such as requests or boto3 to be available.
|
|
75
|
+
c.load("mem://not_there.py")
|
|
76
|
+
|
|
77
|
+
def test_relative(self):
|
|
78
|
+
fileUri = ResourcePath(f"{TESTDIR}/config/relfilename.py", forceAbsolute=True, forceDirectory=False)
|
|
79
|
+
for confFile in (os.path.join(TESTDIR, "config", "relfilename.py"), fileUri, str(fileUri)):
|
|
80
|
+
c = FileConfig()
|
|
81
|
+
c.load(confFile)
|
|
82
|
+
# The __file__ is always the ospath form and should be the file
|
|
83
|
+
# loaded by the config.
|
|
84
|
+
self.assertEqual(c.filename, os.path.join(TESTDIR, "config", "filename.py"))
|
|
85
|
+
self.assertEqual(c.number, 5)
|
|
86
|
+
|
|
87
|
+
c = FileConfig()
|
|
88
|
+
with fileUri.open("r") as fh:
|
|
89
|
+
c.loadFromStream(fh)
|
|
90
|
+
self.assertEqual(c.filename, os.path.join(TESTDIR, "config", "filename.py"))
|
|
91
|
+
self.assertEqual(c.number, 5)
|
|
92
|
+
|
|
93
|
+
c = FileConfig()
|
|
94
|
+
data = fileUri.read()
|
|
95
|
+
with self.assertRaises(FileNotFoundError):
|
|
96
|
+
c.loadFromString(data)
|
|
97
|
+
|
|
98
|
+
c.loadFromString(data, filename=fileUri.ospath)
|
|
99
|
+
self.assertEqual(c.filename, os.path.join(TESTDIR, "config", "filename.py"))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
unittest.main()
|
|
@@ -165,6 +165,20 @@ class ConfigChoiceFieldTest(unittest.TestCase):
|
|
|
165
165
|
with self.assertRaises(pexConfig.UnexpectedProxyUsageError):
|
|
166
166
|
pickle.dumps(self.config.c.names)
|
|
167
167
|
|
|
168
|
+
def test_copy(self):
|
|
169
|
+
"""Test the copy method on a ConfigChoiceField."""
|
|
170
|
+
copy1: Config3 = self.config.copy()
|
|
171
|
+
copy1.a["AAA"].f = 1
|
|
172
|
+
copy1.a["BBB"].f = 1.0
|
|
173
|
+
copy1.a = "BBB"
|
|
174
|
+
self.assertEqual(self.config.a.name, "AAA")
|
|
175
|
+
self.assertEqual(self.config.a.active.f, 4)
|
|
176
|
+
self.assertEqual(self.config.a["AAA"].f, 4)
|
|
177
|
+
self.assertEqual(self.config.a["BBB"].f, 0.5)
|
|
178
|
+
self.assertEqual(copy1.a.name, "BBB")
|
|
179
|
+
self.assertEqual(copy1.a["AAA"].f, 1)
|
|
180
|
+
self.assertEqual(copy1.a["BBB"].f, 1.0)
|
|
181
|
+
|
|
168
182
|
|
|
169
183
|
if __name__ == "__main__":
|
|
170
184
|
unittest.main()
|
|
@@ -207,6 +207,19 @@ class ConfigDictFieldTest(unittest.TestCase):
|
|
|
207
207
|
|
|
208
208
|
self.assertTrue(pexConfig.compareConfigs("test", c1, c2))
|
|
209
209
|
|
|
210
|
+
def test_copy(self):
|
|
211
|
+
"""Test that the copy method works on ConfigDictField instances."""
|
|
212
|
+
original = Config2()
|
|
213
|
+
original.d1 = {"a": Config1, "b": Config1(f=4.0)}
|
|
214
|
+
original.freeze()
|
|
215
|
+
copy1 = original.copy()
|
|
216
|
+
self.assertEqual(copy1.d1["a"].f, 3.0)
|
|
217
|
+
self.assertEqual(copy1.d1["b"].f, 4.0)
|
|
218
|
+
copy1.d1["a"].f = 6.0
|
|
219
|
+
self.assertEqual(copy1.d1["a"].f, 6.0)
|
|
220
|
+
self.assertEqual(copy1.d1["b"].f, 4.0)
|
|
221
|
+
self.assertEqual(original.d1["a"].f, 3.0)
|
|
222
|
+
|
|
210
223
|
|
|
211
224
|
if __name__ == "__main__":
|
|
212
225
|
unittest.main()
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# This file is part of pex_config.
|
|
2
|
-
#
|
|
3
|
-
# Developed for the LSST Data Management System.
|
|
4
|
-
# This product includes software developed by the LSST Project
|
|
5
|
-
# (http://www.lsst.org).
|
|
6
|
-
# See the COPYRIGHT file at the top-level directory of this distribution
|
|
7
|
-
# for details of code ownership.
|
|
8
|
-
#
|
|
9
|
-
# This software is dual licensed under the GNU General Public License and also
|
|
10
|
-
# under a 3-clause BSD license. Recipients may choose which of these licenses
|
|
11
|
-
# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
|
|
12
|
-
# respectively. If you choose the GPL option then the following text applies
|
|
13
|
-
# (but note that there is still no warranty even if you opt for BSD instead):
|
|
14
|
-
#
|
|
15
|
-
# This program is free software: you can redistribute it and/or modify
|
|
16
|
-
# it under the terms of the GNU General Public License as published by
|
|
17
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
18
|
-
# (at your option) any later version.
|
|
19
|
-
#
|
|
20
|
-
# This program is distributed in the hope that it will be useful,
|
|
21
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
22
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
23
|
-
# GNU General Public License for more details.
|
|
24
|
-
#
|
|
25
|
-
# You should have received a copy of the GNU General Public License
|
|
26
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
27
|
-
|
|
28
|
-
import os
|
|
29
|
-
import unittest
|
|
30
|
-
|
|
31
|
-
import lsst.pex.config as pexConf
|
|
32
|
-
|
|
33
|
-
TESTDIR = os.path.dirname(os.path.abspath(__file__))
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class FileConfig(pexConf.Config):
|
|
37
|
-
"""Config used for testing __file__."""
|
|
38
|
-
|
|
39
|
-
number = pexConf.Field("FileConfig.number", int, default=0)
|
|
40
|
-
filename = pexConf.Field("FileConfig.filename", str, default=None)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class FilenameTestCase(unittest.TestCase):
|
|
44
|
-
"""Check that __file__ can be used in a config file."""
|
|
45
|
-
|
|
46
|
-
def test__file(self):
|
|
47
|
-
c = FileConfig()
|
|
48
|
-
confFile = os.path.join(TESTDIR, "config", "filename.py")
|
|
49
|
-
c.load(confFile)
|
|
50
|
-
self.assertEqual(c.filename, confFile)
|
|
51
|
-
self.assertEqual(c.number, 5)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if __name__ == "__main__":
|
|
55
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/design-notes.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/inspecting-configs.rst
RENAMED
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/doc/lsst.pex.config/registry-intro.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/_doNotImportMe.py
RENAMED
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/choiceField.py
RENAMED
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/comparison.py
RENAMED
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configField.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/configurableField.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst/pex/config/rangeField.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst_pex_config.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_pex_config-30.0.0rc2 → lsst_pex_config-30.0.0rc3}/python/lsst_pex_config.egg-info/zip-safe
RENAMED
|
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
|