From 59bbb471a118b0f5aeb75040e5336df09c427334 Mon Sep 17 00:00:00 2001 From: Teresia Olsson Date: Mon, 5 Oct 2026 13:20:30 +0200 Subject: [PATCH 1/3] Rename file resolver to include. --- pyaml/configuration/fileloader.py | 18 +++++++++--------- tests/configuration/test_fileloader.py | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pyaml/configuration/fileloader.py b/pyaml/configuration/fileloader.py index ef5f9f0eb..72b615e11 100644 --- a/pyaml/configuration/fileloader.py +++ b/pyaml/configuration/fileloader.py @@ -189,7 +189,7 @@ def resolver(name: str): Args: name: Prefix used to invoke the resolver (for example ``"env"`` - or ``"file"``). + or ``"include"``). Returns: A decorator that registers the decorated function in the global @@ -266,10 +266,10 @@ def resolve_path(value: str, _context: LoadContext | None = None) -> str: return str(ROOT.expand_path(value)) -@resolver("file") -def resolve_file(value: str, context: LoadContext | None = None) -> Any: +@resolver("include") +def resolve_include(value: str, context: LoadContext | None = None) -> Any: """ - Load and return the contents of a configuration file. + Load and include the contents of a configuration file. Parameters ---------- @@ -289,7 +289,7 @@ def resolve_file(value: str, context: LoadContext | None = None) -> Any: If no loading context is provided. """ if context is None: - raise RuntimeError("File resolver requires LoadContext") + raise RuntimeError("Include resolver requires LoadContext") return _load(value, context) @@ -375,7 +375,7 @@ def _expand_string(self, value: str) -> Any: Expand resolver expressions and file references in a string. If the entire string is a resolver expression (for example - ``"${env:HOME}"`` or ``"${file:config.yaml}"``), the resolved value is + ``"${env:HOME}"`` or ``"${include:config.yaml}"``), the resolved value is returned directly and may be of any type. Resolver expressions embedded inside a larger string are interpolated @@ -425,7 +425,7 @@ def replace(match: re.Match[str]) -> str: value = RESOLVER_PATTERN.sub(replace, value) if _is_supported_file(value): - return RESOLVERS["file"](value, self.context) + return RESOLVERS["include"](value, self.context) return value @@ -434,7 +434,7 @@ def _resolve_resolver_expression(self, expr: str) -> Any: Resolve a single resolver expression. The expression must have the form ``":"``, for - example ``"env:HOME"`` or ``"file:config.yaml"``. The resolver is + example ``"env:HOME"`` or ``"include:config.yaml"``. The resolver is looked up in the global resolver registry and invoked with the supplied payload. @@ -504,7 +504,7 @@ def _expand_list(self, items: list) -> list: for item in items: if isinstance(item, str) and _is_supported_file(item): - loaded = RESOLVERS["file"](item, self.context) + loaded = RESOLVERS["include"](item, self.context) if isinstance(loaded, list): expanded.extend(loaded) else: diff --git a/tests/configuration/test_fileloader.py b/tests/configuration/test_fileloader.py index 53b234a66..25b4c44bd 100644 --- a/tests/configuration/test_fileloader.py +++ b/tests/configuration/test_fileloader.py @@ -132,12 +132,12 @@ def test_load_nested_json(tmp_path): assert result["child"]["answer"] == 42 -def test_load_file_resolver_loads_nested_file(tmp_path): +def test_load_include_resolver_loads_nested_file(tmp_path): ROOT.set(tmp_path) (tmp_path / "subdir").mkdir() (tmp_path / "subdir" / "child.yaml").write_text("answer: 42\n") - (tmp_path / "parent.yaml").write_text('target: "${file:subdir/child.yaml}"\n') + (tmp_path / "parent.yaml").write_text('target: "${include:subdir/child.yaml}"\n') result = load("parent.yaml") @@ -199,11 +199,11 @@ def test_load_path_resolver_resolves_without_loading_file(tmp_path): assert result["target"] == str((tmp_path / "subdir" / "missing.json").resolve()) -def test_load_interpolated_file_resolver_inside_string_raises(tmp_path): +def test_load_interpolated_include_resolver_inside_string_raises(tmp_path): ROOT.set(tmp_path) (tmp_path / "child.yaml").write_text("answer: 42\n") - (tmp_path / "config.yaml").write_text('value: "prefix-${file:child.yaml}-suffix"\n') + (tmp_path / "config.yaml").write_text('value: "prefix-${include:child.yaml}-suffix"\n') with pytest.raises(PyAMLException, match="cannot be interpolated into a string"): load("config.yaml") From 41790b6454050b0d9e1b18e4df3baebceeac198b Mon Sep 17 00:00:00 2001 From: Teresia Olsson Date: Mon, 5 Oct 2026 17:11:34 +0200 Subject: [PATCH 2/3] Remove support for automatic inclusion of files with specific file extensions and require explicit include resolver. --- pyaml/configuration/fileloader.py | 44 ++++++------------- pyaml/configuration/restfetcher.py | 41 ++++++----------- tests/common/test_errors.py | 10 ++--- tests/config/EBSNames-linker.yaml | 2 +- tests/config/EBSNames.yaml | 2 +- tests/config/EBSOrbit.yaml | 2 +- tests/config/EBSTune-patterns.yaml | 2 +- tests/config/EBSTune.yaml | 2 +- tests/config/EBS_rf_multi.yaml | 2 +- tests/config/EBS_rf_notrans.yaml | 2 +- tests/config/bad_conf.yml | 6 +-- tests/config/bad_conf_cycles.json | 8 ++-- tests/config/bad_conf_cycles.yml | 8 ++-- tests/config/bad_conf_duplicate_1.yaml | 6 +-- tests/config/bad_conf_duplicate_2.yaml | 2 +- tests/config/bad_conf_duplicate_3.yaml | 2 +- tests/config/bad_conf_duplicate_4.yaml | 6 +-- tests/config/bpms.yaml | 4 +- tests/config/catalogs/ebs_catalogs.yaml | 12 ++--- tests/config/config_manager_sr_base.yaml | 2 +- tests/config/config_manager_sr_catalogs.yaml | 2 +- tests/config/config_manager_sr_devices.yaml | 4 +- tests/config/sr-attribute-linker.yaml | 6 +-- tests/config/sr-ident-cfm.yaml | 8 ++-- tests/config/sr-range-cfm.yaml | 8 ++-- tests/config/sr.yaml | 6 +-- tests/config/sr/correctors/SH1AC01-C02.yaml | 4 +- tests/config/sr/correctors/SH1AC01-ident.yaml | 2 +- tests/config/sr/correctors/SH1AC01-range.yaml | 2 +- tests/config/sr/correctors/SH1AC01.yaml | 2 +- tests/config/sr/correctors/SH1AC02.yaml | 2 +- tests/config/sr/magnet_models/QF1AC01.json | 2 +- tests/config/sr/magnet_models/QF1AC01.yaml | 2 +- .../sr/quadrupoles/QD5D-C04_serialized.yaml | 2 +- tests/config/sr/quadrupoles/QF1AC01.json | 2 +- tests/config/sr/quadrupoles/QF1AC01.yaml | 2 +- tests/config/sr/quadrupoles/QF1C01A_2.yaml | 2 +- tests/config/tune_monitor.yaml | 2 +- .../test_configuration_manager.py | 2 +- tests/configuration/test_fileloader.py | 21 +++------ tests/test_accelerator_load.py | 2 +- 41 files changed, 105 insertions(+), 145 deletions(-) diff --git a/pyaml/configuration/fileloader.py b/pyaml/configuration/fileloader.py index 72b615e11..c8b09aa96 100644 --- a/pyaml/configuration/fileloader.py +++ b/pyaml/configuration/fileloader.py @@ -29,7 +29,6 @@ LOCATION_KEY = "__location__" FIELD_LOCATIONS_KEY = "__fieldlocations__" -ACCEPTED_SUFFIXES = (".yaml", ".yml", ".json") RESOLVER_PATTERN = re.compile(r"\$\{([^{}]+)\}") @@ -323,11 +322,6 @@ def _load(filename: str, context: LoadContext) -> Union[dict, list]: return loader.load() -def _is_supported_file(value: Any) -> bool: - """Return True if the value looks like a supported configuration file name.""" - return isinstance(value, str) and value.endswith(ACCEPTED_SUFFIXES) - - class ConfigLoader(ABC): """ Base class for parsers that expand nested configuration references. @@ -424,9 +418,6 @@ def replace(match: re.Match[str]) -> str: value = RESOLVER_PATTERN.sub(replace, value) - if _is_supported_file(value): - return RESOLVERS["include"](value, self.context) - return value def _resolve_resolver_expression(self, expr: str) -> Any: @@ -487,31 +478,24 @@ def _expand_list(self, items: list) -> list: """ Recursively expand the elements of a list. - Plain string values that refer to supported configuration files are - treated as list includes. If the referenced file loads to a list, its - elements are spliced into the current list. Otherwise, the loaded - object is appended as a single element. - - All other items are expanded recursively using :meth:`expand`. - - Args: - items: The list to expand. - - Returns: - The expanded list. + Lists returned by an explicit include resolver are spliced into the + current list. Other nested lists are preserved. """ expanded: list[Any] = [] for item in items: - if isinstance(item, str) and _is_supported_file(item): - loaded = RESOLVERS["include"](item, self.context) - if isinstance(loaded, list): - expanded.extend(loaded) - else: - expanded.append(loaded) - continue - - expanded.append(self.expand(item)) + is_include = ( + isinstance(item, str) + and (match := RESOLVER_PATTERN.fullmatch(item)) is not None + and match.group(1).strip().startswith("include:") + ) + + value = self.expand(item) + + if is_include and isinstance(value, list): + expanded.extend(value) + else: + expanded.append(value) return expanded diff --git a/pyaml/configuration/restfetcher.py b/pyaml/configuration/restfetcher.py index 96a754502..0ae0612f6 100644 --- a/pyaml/configuration/restfetcher.py +++ b/pyaml/configuration/restfetcher.py @@ -18,12 +18,12 @@ from yaml import CLoader from ..common.exception import PyAMLConfigException -from .fileloader import ACCEPTED_SUFFIXES, SafeLineLoader +from .fileloader import SafeLineLoader REMOTE_BASE_URL_KEY = "__baseurl__" SourceRoot = Path | str | None _REMOTE_SCHEMES = {"http", "https"} - +INCLUDE_PREFIX = "${include:" FILE_PREFIX = "${path:" @@ -285,9 +285,10 @@ def _expand_remote_dict( """ values.setdefault(REMOTE_BASE_URL_KEY, base_url) for key, value in list(values.items()): - if _is_config_reference(value): + if _is_include(value): + reference = _include_reference(value) values[key] = _load_remote_document( - _resolve_remote_config_reference(value, base_url), + _resolve_remote_config_reference(reference, base_url), include_locations=include_locations, stack=stack, ) @@ -324,9 +325,10 @@ def _expand_remote_list(values: list[Any], base_url: str, stack: list[str], *, i index = 0 while index < len(values): value = values[index] - if _is_config_reference(value): + if _is_include(value): + reference = _include_reference(value) expanded = _load_remote_document( - _resolve_remote_config_reference(value, base_url), + _resolve_remote_config_reference(reference, base_url), include_locations=include_locations, stack=stack, ) @@ -348,29 +350,14 @@ def _expand_remote_list(values: list[Any], base_url: str, stack: list[str], *, i return values -def _is_config_reference(value: Any) -> bool: - """ - Return whether a value names a supported configuration document. - - Parameters - ---------- - value : Any - Value to inspect. - - Returns - ------- - bool - ``True`` for a YAML, JSON, or supported remote document reference. - """ - if not isinstance(value, str): - return False +def _is_include(value: Any) -> bool: + """Return whether a value is an explicit include expression.""" + return isinstance(value, str) and value.startswith(INCLUDE_PREFIX) and value.endswith("}") - if value.startswith(FILE_PREFIX): - return False - parsed = urlparse(value) - path = parsed.path if parsed.scheme in _REMOTE_SCHEMES else value - return any(path.endswith(suffix) for suffix in ACCEPTED_SUFFIXES) +def _include_reference(value: str) -> str: + """Return the reference contained in an include expression.""" + return value[len(INCLUDE_PREFIX) : -1].strip() def _resolve_remote_config_reference(reference: str, base_url: str) -> str: diff --git a/tests/common/test_errors.py b/tests/common/test_errors.py index 38ce79f56..37814410c 100644 --- a/tests/common/test_errors.py +++ b/tests/common/test_errors.py @@ -60,7 +60,7 @@ def test_duplicate_error_reports_source_line_and_column_across_files(tmp_path): ) root = tmp_path / "root.yaml" root.write_text( - "type: pyaml.accelerator\ndevices:\n - devices_a.yaml\n - devices_b.yaml\n", + "type: pyaml.accelerator\ndevices:\n - ${include:devices_a.yaml}\n - ${include:devices_b.yaml}\n", encoding="utf-8", ) @@ -86,7 +86,7 @@ def test_malformed_local_included_yaml_reports_source_line_and_column(tmp_path): "machine: sr\n" "energy: 6e9\n" "data_folder: /data/store\n" - "devices: broken_devices.yaml\n", + "devices: ${include:broken_devices.yaml}\n", encoding="utf-8", ) @@ -111,7 +111,7 @@ def test_truncated_local_included_json_reports_source_and_position(tmp_path): "machine: sr\n" "energy: 6e9\n" "data_folder: /data/store\n" - "devices: broken_devices.json\n", + "devices: ${include:broken_devices.json}\n", encoding="utf-8", ) @@ -131,7 +131,7 @@ def test_malformed_remote_included_yaml_reports_source_line_and_column(http_conf "machine: sr\n" "energy: 6000000000.0\n" "data_folder: /data/store\n" - "devices: fragments/broken_devices.yaml\n" + "devices: ${include:fragments/broken_devices.yaml}\n" ), "/configs/fragments/broken_devices.yaml": ("- type: pyaml.bpm.bpm\n name: BPM_BROKEN\n model:\n type: [oops\n"), } @@ -153,7 +153,7 @@ def test_truncated_remote_included_json_reports_source_and_position(http_config_ "machine: sr\n" "energy: 6000000000.0\n" "data_folder: /data/store\n" - "devices: fragments/broken_devices.json\n" + "devices: ${include:fragments/broken_devices.json}\n" ), "/configs/fragments/broken_devices.json": ( '{"type": "pyaml.bpm.bpm", "name": "BPM_BROKEN", "model": ', diff --git a/tests/config/EBSNames-linker.yaml b/tests/config/EBSNames-linker.yaml index 98ae50b29..e322320e1 100644 --- a/tests/config/EBSNames-linker.yaml +++ b/tests/config/EBSNames-linker.yaml @@ -13,7 +13,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.magnet.quadrupole diff --git a/tests/config/EBSNames.yaml b/tests/config/EBSNames.yaml index b0eee6afc..cde710651 100644 --- a/tests/config/EBSNames.yaml +++ b/tests/config/EBSNames.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.magnet.quadrupole diff --git a/tests/config/EBSOrbit.yaml b/tests/config/EBSOrbit.yaml index 5d6ea2570..3a6516cfe 100644 --- a/tests/config/EBSOrbit.yaml +++ b/tests/config/EBSOrbit.yaml @@ -11,7 +11,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet diff --git a/tests/config/EBSTune-patterns.yaml b/tests/config/EBSTune-patterns.yaml index 0c258bdea..c0bad0f4c 100644 --- a/tests/config/EBSTune-patterns.yaml +++ b/tests/config/EBSTune-patterns.yaml @@ -12,7 +12,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet diff --git a/tests/config/EBSTune.yaml b/tests/config/EBSTune.yaml index f5a8d5c08..52c7d0119 100644 --- a/tests/config/EBSTune.yaml +++ b/tests/config/EBSTune.yaml @@ -12,7 +12,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet diff --git a/tests/config/EBS_rf_multi.yaml b/tests/config/EBS_rf_multi.yaml index d3c7133be..f1025118b 100644 --- a/tests/config/EBS_rf_multi.yaml +++ b/tests/config/EBS_rf_multi.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.rf.rf_plant diff --git a/tests/config/EBS_rf_notrans.yaml b/tests/config/EBS_rf_notrans.yaml index 1306d8c28..daff32790 100644 --- a/tests/config/EBS_rf_notrans.yaml +++ b/tests/config/EBS_rf_notrans.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.rf.rf_plant diff --git a/tests/config/bad_conf.yml b/tests/config/bad_conf.yml index 178733b4a..513aafebe 100644 --- a/tests/config/bad_conf.yml +++ b/tests/config/bad_conf.yml @@ -19,6 +19,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bad_conf_cycles.json b/tests/config/bad_conf_cycles.json index 26af53c1f..11f0d6498 100644 --- a/tests/config/bad_conf_cycles.json +++ b/tests/config/bad_conf_cycles.json @@ -3,7 +3,7 @@ "facility": "ESRF", "machine": "sr", "energy": 6e9, - "simulators": ["../config/bad_conf_cycles.json"], + "simulators": ["${include:../config/bad_conf_cycles.json}"], "data_folder": "/data/store", "arrays": [ { @@ -21,8 +21,8 @@ } ], "devices": [ - "sr/quadrupoles/QF1AC01.yaml", - "sr/correctors/SH1AC01.yaml", - "sr/correctors/SH1AC02.yaml" + "${include:sr/quadrupoles/QF1AC01.yaml}", + "${include:sr/correctors/SH1AC01.yaml}", + "${include:sr/correctors/SH1AC02.yaml}" ] } diff --git a/tests/config/bad_conf_cycles.yml b/tests/config/bad_conf_cycles.yml index c0361864a..7cfa167d3 100644 --- a/tests/config/bad_conf_cycles.yml +++ b/tests/config/bad_conf_cycles.yml @@ -19,7 +19,7 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - ../config/bad_conf_cycles.yml # Cycle here - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:../config/bad_conf_cycles.yml} # Cycle here + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bad_conf_duplicate_1.yaml b/tests/config/bad_conf_duplicate_1.yaml index 209c3be09..608d07655 100644 --- a/tests/config/bad_conf_duplicate_1.yaml +++ b/tests/config/bad_conf_duplicate_1.yaml @@ -20,6 +20,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bad_conf_duplicate_2.yaml b/tests/config/bad_conf_duplicate_2.yaml index 346957aa8..830de340c 100644 --- a/tests/config/bad_conf_duplicate_2.yaml +++ b/tests/config/bad_conf_duplicate_2.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.bpm diff --git a/tests/config/bad_conf_duplicate_3.yaml b/tests/config/bad_conf_duplicate_3.yaml index 9149009fb..872ab1220 100644 --- a/tests/config/bad_conf_duplicate_3.yaml +++ b/tests/config/bad_conf_duplicate_3.yaml @@ -12,7 +12,7 @@ controls: name: live catalog: bpm-catalog catalogs: - - catalogs/sr_catalogs.yaml + - ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.bpm diff --git a/tests/config/bad_conf_duplicate_4.yaml b/tests/config/bad_conf_duplicate_4.yaml index 95beb2f24..fc1faad04 100644 --- a/tests/config/bad_conf_duplicate_4.yaml +++ b/tests/config/bad_conf_duplicate_4.yaml @@ -19,6 +19,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bpms.yaml b/tests/config/bpms.yaml index 07caf59af..343474839 100644 --- a/tests/config/bpms.yaml +++ b/tests/config/bpms.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.bpm.bpm @@ -42,4 +42,4 @@ devices: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] - model: sr/magnet_models/SH1AC01.yaml + model: ${include:sr/magnet_models/SH1AC01.yaml} diff --git a/tests/config/catalogs/ebs_catalogs.yaml b/tests/config/catalogs/ebs_catalogs.yaml index d15349d6f..b3da9a0d4 100644 --- a/tests/config/catalogs/ebs_catalogs.yaml +++ b/tests/config/catalogs/ebs_catalogs.yaml @@ -1,8 +1,8 @@ type: tango.pyaml.static_catalog entries: - - catalogs/ebs_bpm_catalogs.yaml - - catalogs/ebs_rf_catalogs.yaml - - catalogs/ebs_diag_catalogs.yaml - - catalogs/ebs_magnets_catalogs.yaml - - catalogs/ebs_sh_catalogs.yaml - - catalogs/ebs_sext_catalogs.yaml + - ${include:catalogs/ebs_bpm_catalogs.yaml} + - ${include:catalogs/ebs_rf_catalogs.yaml} + - ${include:catalogs/ebs_diag_catalogs.yaml} + - ${include:catalogs/ebs_magnets_catalogs.yaml} + - ${include:catalogs/ebs_sh_catalogs.yaml} + - ${include:catalogs/ebs_sext_catalogs.yaml} diff --git a/tests/config/config_manager_sr_base.yaml b/tests/config/config_manager_sr_base.yaml index c842221ac..0d829bfda 100644 --- a/tests/config/config_manager_sr_base.yaml +++ b/tests/config/config_manager_sr_base.yaml @@ -10,5 +10,5 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store diff --git a/tests/config/config_manager_sr_catalogs.yaml b/tests/config/config_manager_sr_catalogs.yaml index 2a0f93347..6fae41e5f 100644 --- a/tests/config/config_manager_sr_catalogs.yaml +++ b/tests/config/config_manager_sr_catalogs.yaml @@ -1,2 +1,2 @@ catalogs: - - catalogs/sr_catalogs.yaml + - ${include:catalogs/sr_catalogs.yaml} diff --git a/tests/config/config_manager_sr_devices.yaml b/tests/config/config_manager_sr_devices.yaml index c6d3e2124..20b8fd9a5 100644 --- a/tests/config/config_manager_sr_devices.yaml +++ b/tests/config/config_manager_sr_devices.yaml @@ -1,6 +1,6 @@ devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-C02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-C02.yaml} - type: pyaml.bpm.bpm name: BPM_C04-01 x_pos: srdiag/bpm/c04-01/SA_HPosition diff --git a/tests/config/sr-attribute-linker.yaml b/tests/config/sr-attribute-linker.yaml index 1eb8edbbf..98d531d8c 100644 --- a/tests/config/sr-attribute-linker.yaml +++ b/tests/config/sr-attribute-linker.yaml @@ -22,6 +22,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/sr-ident-cfm.yaml b/tests/config/sr-ident-cfm.yaml index 7bc833fdf..11e0fbd4c 100644 --- a/tests/config/sr-ident-cfm.yaml +++ b/tests/config/sr-ident-cfm.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -24,6 +24,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-ident.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-ident.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/sr-range-cfm.yaml b/tests/config/sr-range-cfm.yaml index fc1b37217..466531e79 100644 --- a/tests/config/sr-range-cfm.yaml +++ b/tests/config/sr-range-cfm.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -24,6 +24,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-range.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-range.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/sr.yaml b/tests/config/sr.yaml index 3e9561e81..05dc9699f 100644 --- a/tests/config/sr.yaml +++ b/tests/config/sr.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -41,8 +41,8 @@ arrays: - SH1A-C01-V - SH1A-C02-H devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-C02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-C02.yaml} - type: pyaml.bpm.bpm name: BPM_C04-01 x_pos: srdiag/bpm/c04-01/SA_HPosition diff --git a/tests/config/sr/correctors/SH1AC01-C02.yaml b/tests/config/sr/correctors/SH1AC01-C02.yaml index 0bba2e4f0..295d1e520 100644 --- a/tests/config/sr/correctors/SH1AC01-C02.yaml +++ b/tests/config/sr/correctors/SH1AC01-C02.yaml @@ -8,7 +8,7 @@ - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] - model: sr/magnet_models/SH1AC01.yaml + model: ${include:sr/magnet_models/SH1AC01.yaml} - type: pyaml.magnet.cfm_magnet name: SH1A-C02 #Name of the element in the lattice model mapping: @@ -19,4 +19,4 @@ - [B0, SH1A-C02-H] - [A0, SH1A-C02-V] - [A1, SH1A-C02-SQ] - model: sr/magnet_models/SH1AC02.yaml + model: ${include:sr/magnet_models/SH1AC02.yaml} diff --git a/tests/config/sr/correctors/SH1AC01-ident.yaml b/tests/config/sr/correctors/SH1AC01-ident.yaml index f5f568953..0f634c2a9 100644 --- a/tests/config/sr/correctors/SH1AC01-ident.yaml +++ b/tests/config/sr/correctors/SH1AC01-ident.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] -model: sr/magnet_models/SH1AC01-ident.yaml +model: ${include:sr/magnet_models/SH1AC01-ident.yaml} diff --git a/tests/config/sr/correctors/SH1AC01-range.yaml b/tests/config/sr/correctors/SH1AC01-range.yaml index ff9eeee85..0cffc86c2 100644 --- a/tests/config/sr/correctors/SH1AC01-range.yaml +++ b/tests/config/sr/correctors/SH1AC01-range.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] -model: sr/magnet_models/SH1AC01-range.yaml +model: ${include:sr/magnet_models/SH1AC01-range.yaml} diff --git a/tests/config/sr/correctors/SH1AC01.yaml b/tests/config/sr/correctors/SH1AC01.yaml index 717ad973d..9facc0bec 100644 --- a/tests/config/sr/correctors/SH1AC01.yaml +++ b/tests/config/sr/correctors/SH1AC01.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] -model: sr/magnet_models/SH1AC01.yaml +model: ${include:sr/magnet_models/SH1AC01.yaml} diff --git a/tests/config/sr/correctors/SH1AC02.yaml b/tests/config/sr/correctors/SH1AC02.yaml index 590d69b93..3818d5ade 100644 --- a/tests/config/sr/correctors/SH1AC02.yaml +++ b/tests/config/sr/correctors/SH1AC02.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C02-H] - [A0, SH1A-C02-V] - [A1, SH1A-C02-SQ] -model: sr/magnet_models/SH1AC02.yaml +model: ${include:sr/magnet_models/SH1AC02.yaml} diff --git a/tests/config/sr/magnet_models/QF1AC01.json b/tests/config/sr/magnet_models/QF1AC01.json index b9b4e8abd..966a5a459 100644 --- a/tests/config/sr/magnet_models/QF1AC01.json +++ b/tests/config/sr/magnet_models/QF1AC01.json @@ -2,7 +2,7 @@ "type": "pyaml.magnet.linear_model", "calibration_factor": 1.00504, "calibration_offset": 0.0, - "curve": "sr/magnet_models/quadcurve.json", + "curve": "${include:sr/magnet_models/quadcurve.json}", "unit": "1/m", "hardware_unit": "A", "powerconverter": "sr/ps-qf1/c01-a/current" diff --git a/tests/config/sr/magnet_models/QF1AC01.yaml b/tests/config/sr/magnet_models/QF1AC01.yaml index c2f1ac30c..8d31dee13 100644 --- a/tests/config/sr/magnet_models/QF1AC01.yaml +++ b/tests/config/sr/magnet_models/QF1AC01.yaml @@ -1,7 +1,7 @@ type: pyaml.magnet.linear_model calibration_factor: 1.00504 calibration_offset: 0.0 -curve: sr/magnet_models/quadcurve.yaml +curve: ${include:sr/magnet_models/quadcurve.yaml} unit: 1/m hardware_unit: A powerconverter: sr/ps-qf1/c01-a/current diff --git a/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml b/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml index 18f5a9123..48dcc7e2a 100644 --- a/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml +++ b/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml @@ -1,6 +1,6 @@ type: pyaml.magnet.quadrupole name: QD5D-C04 -model: sr/magnet_models/QF1AC01.yaml +model: ${include:sr/magnet_models/QF1AC01.yaml} linked_elements: - QF8B-C04 - QF8D-C04 diff --git a/tests/config/sr/quadrupoles/QF1AC01.json b/tests/config/sr/quadrupoles/QF1AC01.json index 655d06994..164fdccda 100644 --- a/tests/config/sr/quadrupoles/QF1AC01.json +++ b/tests/config/sr/quadrupoles/QF1AC01.json @@ -1,5 +1,5 @@ { "type": "pyaml.magnet.quadrupole", "name": "QF1A-C01", - "model": "sr/magnet_models/QF1AC01.json" + "model": "${include:sr/magnet_models/QF1AC01.json}" } diff --git a/tests/config/sr/quadrupoles/QF1AC01.yaml b/tests/config/sr/quadrupoles/QF1AC01.yaml index 627702adc..507d3d9dc 100644 --- a/tests/config/sr/quadrupoles/QF1AC01.yaml +++ b/tests/config/sr/quadrupoles/QF1AC01.yaml @@ -1,3 +1,3 @@ type: pyaml.magnet.quadrupole name: QF1A-C01 -model: sr/magnet_models/QF1AC01.yaml +model: ${include:sr/magnet_models/QF1AC01.yaml} diff --git a/tests/config/sr/quadrupoles/QF1C01A_2.yaml b/tests/config/sr/quadrupoles/QF1C01A_2.yaml index 6ab7f120d..6c9c21e78 100644 --- a/tests/config/sr/quadrupoles/QF1C01A_2.yaml +++ b/tests/config/sr/quadrupoles/QF1C01A_2.yaml @@ -4,7 +4,7 @@ model: type: pyaml.magnet.linear_model calibration_factor: 1.006560 calibration_offset: 0.0034 - curve: sr/magnet_models/quadcurve.yaml + curve: ${include:sr/magnet_models/quadcurve.yaml} unit: 1/m hardware_unit: A powerconverter: sr/ps-qf1/c01-a/current diff --git a/tests/config/tune_monitor.yaml b/tests/config/tune_monitor.yaml index f782a2c1c..791a62dee 100644 --- a/tests/config/tune_monitor.yaml +++ b/tests/config/tune_monitor.yaml @@ -11,7 +11,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.diagnostics.tune_monitor diff --git a/tests/configuration/test_configuration_manager.py b/tests/configuration/test_configuration_manager.py index f36c37dd1..a8c98ec20 100644 --- a/tests/configuration/test_configuration_manager.py +++ b/tests/configuration/test_configuration_manager.py @@ -222,7 +222,7 @@ def test_configuration_manager_adds_remote_source_with_relative_includes(http_co energy: 3000000000.0 data_folder: remote-data description: Loaded over HTTP -simulators: fragments/simulators.json +simulators: ${include:fragments/simulators.json} devices: [] """, "/configs/fragments/simulators.json": """ diff --git a/tests/configuration/test_fileloader.py b/tests/configuration/test_fileloader.py index 25b4c44bd..6fae602a0 100644 --- a/tests/configuration/test_fileloader.py +++ b/tests/configuration/test_fileloader.py @@ -9,7 +9,6 @@ ROOT, LoadContext, RootFolder, - _is_supported_file, load, ) @@ -54,16 +53,6 @@ def test_rootfolder_set_updates_root(tmp_path): assert after == (new_root / "config.yaml").resolve() -def test_is_supported_file(): - assert _is_supported_file("config.yaml") - assert _is_supported_file("config.yml") - assert _is_supported_file("config.json") - - assert not _is_supported_file("config.txt") - assert not _is_supported_file(1) - assert not _is_supported_file(None) - - def test_load_context_adds_and_removes_paths(tmp_path): ctx = LoadContext() path = tmp_path / "config.yaml" @@ -113,7 +102,7 @@ def test_load_nested_yaml(tmp_path): (tmp_path / "child.yaml").write_text("answer: 42\n") - (tmp_path / "parent.yaml").write_text("child: child.yaml\n") + (tmp_path / "parent.yaml").write_text("child: ${include:child.yaml}\n") result = load("parent.yaml") @@ -125,7 +114,7 @@ def test_load_nested_json(tmp_path): (tmp_path / "child.json").write_text(json.dumps({"answer": 42})) - (tmp_path / "parent.json").write_text(json.dumps({"child": "child.json"})) + (tmp_path / "parent.json").write_text(json.dumps({"child": "${include:child.json}"})) result = load("parent.json") @@ -227,7 +216,7 @@ def test_load_list_include_extends_list(tmp_path): """ values: - start - - items.yaml + - ${include:items.yaml} - end """.strip() ) @@ -285,8 +274,8 @@ def test_load_invalid_json_raises_pyaml_exception(tmp_path): def test_load_circular_include_raises_pyaml_exception(tmp_path): ROOT.set(tmp_path) - (tmp_path / "a.yaml").write_text("b: b.yaml\n") - (tmp_path / "b.yaml").write_text("a: a.yaml\n") + (tmp_path / "a.yaml").write_text("b: ${include:b.yaml}\n") + (tmp_path / "b.yaml").write_text("a: ${include:a.yaml}\n") with pytest.raises(PyAMLException, match="Circular file inclusion"): load("a.yaml") diff --git a/tests/test_accelerator_load.py b/tests/test_accelerator_load.py index f30a68e39..caedcb249 100644 --- a/tests/test_accelerator_load.py +++ b/tests/test_accelerator_load.py @@ -73,7 +73,7 @@ def test_accelerator_load_supports_remote_sources(http_config_server, ebs_lattic energy: 3000000000.0 data_folder: remote-data description: Remote accelerator -simulators: fragments/simulators.json +simulators: ${include:fragments/simulators.json} devices: [] """, "/config/fragments/simulators.json": f""" From 836eb545701f1325acc88e1a3ce0f97555451880 Mon Sep 17 00:00:00 2001 From: Teresia Olsson Date: Mon, 5 Oct 2026 17:29:00 +0200 Subject: [PATCH 3/3] Update example configurations to new syntax. --- .../use_cases/config/esrf/catalogs/ebs_catalogs.yaml | 12 ++++++------ examples/use_cases/config/esrf/esrf.yaml | 2 +- examples/use_cases/config/soleil_ii/p.yaml | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml b/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml index d15349d6f..b3da9a0d4 100644 --- a/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml +++ b/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml @@ -1,8 +1,8 @@ type: tango.pyaml.static_catalog entries: - - catalogs/ebs_bpm_catalogs.yaml - - catalogs/ebs_rf_catalogs.yaml - - catalogs/ebs_diag_catalogs.yaml - - catalogs/ebs_magnets_catalogs.yaml - - catalogs/ebs_sh_catalogs.yaml - - catalogs/ebs_sext_catalogs.yaml + - ${include:catalogs/ebs_bpm_catalogs.yaml} + - ${include:catalogs/ebs_rf_catalogs.yaml} + - ${include:catalogs/ebs_diag_catalogs.yaml} + - ${include:catalogs/ebs_magnets_catalogs.yaml} + - ${include:catalogs/ebs_sh_catalogs.yaml} + - ${include:catalogs/ebs_sext_catalogs.yaml} diff --git a/examples/use_cases/config/esrf/esrf.yaml b/examples/use_cases/config/esrf/esrf.yaml index a3bdba75a..57b952ead 100644 --- a/examples/use_cases/config/esrf/esrf.yaml +++ b/examples/use_cases/config/esrf/esrf.yaml @@ -11,7 +11,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet diff --git a/examples/use_cases/config/soleil_ii/p.yaml b/examples/use_cases/config/soleil_ii/p.yaml index d8829096d..3eab94047 100644 --- a/examples/use_cases/config/soleil_ii/p.yaml +++ b/examples/use_cases/config/soleil_ii/p.yaml @@ -14,8 +14,8 @@ controls: - type: tango.pyaml.controlsystem name: live tango_host: localhost:11000 - catalog: catalogs.yaml -arrays: arrays.yaml + catalog: ${include:catalogs.yaml} +arrays: ${include:arrays.yaml} devices: -- devices.yaml -- tuning_tools.yaml +- ${include:devices.yaml} +- ${include:tuning_tools.yaml}