From 33b8c75f5441da8e58a938cb732589d627fc33e8 Mon Sep 17 00:00:00 2001 From: kparasch Date: Fri, 18 Sep 2026 10:20:13 +0200 Subject: [PATCH 1/3] first example of template --- examples/template/templated_config.yaml | 24 ++++++++++++++ pyaml/configuration/factory.py | 12 ++++++- pyaml/configuration/template.py | 44 +++++++++++++++++++++++++ pyaml/validation/validation_models.py | 7 +++- 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 examples/template/templated_config.yaml create mode 100644 pyaml/configuration/template.py diff --git a/examples/template/templated_config.yaml b/examples/template/templated_config.yaml new file mode 100644 index 00000000..b9c8b3e4 --- /dev/null +++ b/examples/template/templated_config.yaml @@ -0,0 +1,24 @@ +- class: pyaml.configuration.template.Template + template: | + class: pyaml.magnet.hcorrector.HCorrector + name: %template_parameter% + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + unit: rad + hardware_unit: str + calibration_factor: 1.0 + powerconverter: MAGNET/%template_parameter%/B1L + string_to_replace: "%template_parameter%" + parameter_list: + - PKDK_WL_108 + - PKDK_WL_93 + - PKDK_WL_79 + - PKDK_WL_64 +- class: pyaml.magnet.hcorrector.HCorrector + name: ANOTHER + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + unit: rad + hardware_unit: str + calibration_factor: 1.0 + powerconverter: MAGNET/ANOTHER/B1L diff --git a/pyaml/configuration/factory.py b/pyaml/configuration/factory.py index 445ce966..3345569b 100644 --- a/pyaml/configuration/factory.py +++ b/pyaml/configuration/factory.py @@ -396,7 +396,17 @@ def _build_list(self, items: list[Any], ignore_external: bool = False): ignore_external : bool If ``True``, ignore unavailable external modules. """ - return [self._build(item, ignore_external) for item in items] + list_out = [] + for item in items: + obj = self._build(item, ignore_external) + from collections.abc import Iterator + + if isinstance(obj, Iterator): + expanded_iterator = [*obj] + list_out.extend(expanded_iterator) + else: + list_out.append(obj) + return list_out def _build_dict(self, data: dict, ignore_external: bool = False): """ diff --git a/pyaml/configuration/template.py b/pyaml/configuration/template.py new file mode 100644 index 00000000..e49f6a2d --- /dev/null +++ b/pyaml/configuration/template.py @@ -0,0 +1,44 @@ +import json +import logging + +import yaml +from pydantic import BaseModel + +from pyaml.configuration.factory import Factory +from pyaml.validation import StaticValidation, register_schema + +from ..common.exception import PyAMLConfigException + +logger = logging.getLogger(__name__) + + +def load_json_or_yaml(string_to_load: str) -> dict: + try: + loaded_dict = json.loads(string_to_load) + return "json" + except json.JSONDecodeError: + pass + + try: + loaded_dict = yaml.safe_load(string_to_load) + except yaml.YAMLError as exc: + raise PyAMLConfigException("Template class is not a valid YAML or JSON string.") from exc + + return loaded_dict + + +class TemplateValidationModel(BaseModel): + template: str + string_to_replace: str + parameter_list: list[str] + + +@register_schema +class Template(StaticValidation): + validation_model = TemplateValidationModel + + def __new__(cls, template: str, string_to_replace: str, parameter_list: list[str]): + for par in parameter_list: + new_string = template.replace(string_to_replace, par) + new_dict = load_json_or_yaml(new_string) + yield Factory.build(new_dict) diff --git a/pyaml/validation/validation_models.py b/pyaml/validation/validation_models.py index 8c5d7703..1bd682da 100644 --- a/pyaml/validation/validation_models.py +++ b/pyaml/validation/validation_models.py @@ -111,7 +111,12 @@ def __call__(cls, *args: Any, **kwargs: Any): raise TypeError(f"{cls.__name__} must define validation_model.") # Inspect the signature of the class - signature = inspect.signature(cls.__init__) + if "__init__" in cls.__dict__: + signature = inspect.signature(cls.__init__) + elif "__new__" in cls.__dict__: + signature = inspect.signature(cls.__new__) + else: + raise Exception # Map arguments to parameters bound = signature.bind(None, *args, **kwargs) From 0b05e0c41d510906c7f101b0d3a6d603afcf1a78 Mon Sep 17 00:00:00 2001 From: kparasch Date: Fri, 18 Sep 2026 10:26:24 +0200 Subject: [PATCH 2/3] fix absolute imports and remove logger --- pyaml/configuration/template.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pyaml/configuration/template.py b/pyaml/configuration/template.py index e49f6a2d..eb81eea0 100644 --- a/pyaml/configuration/template.py +++ b/pyaml/configuration/template.py @@ -1,15 +1,11 @@ import json -import logging import yaml from pydantic import BaseModel -from pyaml.configuration.factory import Factory -from pyaml.validation import StaticValidation, register_schema - from ..common.exception import PyAMLConfigException - -logger = logging.getLogger(__name__) +from ..configuration.factory import Factory +from ..validation import StaticValidation, register_schema def load_json_or_yaml(string_to_load: str) -> dict: From 6787dd4ed9271c11b590f23ff9d3e2b74486dd44 Mon Sep 17 00:00:00 2001 From: kparasch Date: Fri, 18 Sep 2026 13:52:27 +0200 Subject: [PATCH 3/3] forgot to put example script --- examples/template/build_template_example.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 examples/template/build_template_example.py diff --git a/examples/template/build_template_example.py b/examples/template/build_template_example.py new file mode 100644 index 00000000..01967b9c --- /dev/null +++ b/examples/template/build_template_example.py @@ -0,0 +1,8 @@ +import yaml + +from pyaml.configuration.factory import Factory + +cc = yaml.safe_load(open("templated_config.yaml")) + +obj = Factory.build(cc) +print(obj)