diff --git a/baybe/settings.py b/baybe/settings.py index 1f553acb6c..3fa68029dc 100644 --- a/baybe/settings.py +++ b/baybe/settings.py @@ -77,6 +77,40 @@ def inner(*args, **kwds): return inner +def _make_default_factory(fld: Attribute, /) -> Any: + """Make the default factory for the given attribute.""" + # TODO: https://github.com/python-attrs/attrs/issues/1540 + name = fld.alias or fld.name + + def get_default_value(self: Settings) -> Any: + """Dynamically retrieve the default value for the field. + + Depending on the control flags, the value is retrieved either from the + field specification itself, from the corresponding environment variable, + or from the active settings object. + """ + if self._restore_defaults: + default = fld.default + else: + # Here, the active settings value is used as default, to + # enable updating settings one attribute at a time (the fallback to + # the default happens when the active settings object is itself + # being created) + default = getattr(active_settings, fld.name, fld.default) + + if self._restore_environment: + # If enabled, the environment values take precedence for the default + env_name = f"BAYBE_{name.upper()}" + value = os.getenv(env_name, default) + if fld.type == "bool": + value = to_bool(value) + return value + + return default + + return Factory(get_default_value, takes_self=True) + + def adjust_defaults(cls: type[Settings], fields: list[Attribute]) -> list[Attribute]: """Replace default values with the appropriate source, controlled via flags.""" results = [] @@ -87,39 +121,7 @@ def adjust_defaults(cls: type[Settings], fields: list[Attribute]) -> list[Attrib # We use a factory here because the environment variables should be looked up # at instantiation time, not at class definition time - def make_default_factory(fld: Attribute) -> Any: - # TODO: https://github.com/python-attrs/attrs/issues/1479 - name = fld.alias or fld.name - - def get_default_value(self: Settings) -> Any: - """Dynamically retrieve the default value for the field. - - Depending on the control flags, the value is retrieved either from the - field specification itself, from the corresponding environment variable, - or from the active settings object. - """ - if self._restore_defaults: - default = fld.default - else: - # Here, the active settings value is used as default, to - # enable updating settings one attribute at a time (the fallback to - # the default happens when the active settings object is itself - # being created) - default = getattr(active_settings, fld.name, fld.default) - - if self._restore_environment: - # If enabled, the environment values take precedence for the default - env_name = f"BAYBE_{name.upper()}" - value = os.getenv(env_name, default) - if fld.type == "bool": - value = to_bool(value) - return value - - return default - - return Factory(get_default_value, takes_self=True) - - results.append(fld.evolve(default=make_default_factory(fld))) + results.append(fld.evolve(default=_make_default_factory(fld))) return results @@ -227,11 +229,14 @@ def __attrs_pre_init__(self) -> None: ("BAYBE_CACHE_DIR", flds.cache_directory), ] for env_var, fld in pairs: + # TODO: https://github.com/python-attrs/attrs/issues/1540 + name = fld.alias or fld.name + if (value := os.environ.pop(env_var, None)) is not None: warnings.warn( f"The environment variable '{env_var}' has " f"been deprecated and support will be dropped in a future version. " - f"Please use 'BAYBE_{(fld.alias or fld.name).upper()}' instead. " + f"Please use 'BAYBE_{name.upper()}' instead. " f"For now, we've automatically handled the translation for you.", DeprecationWarning, ) @@ -239,7 +244,7 @@ def __attrs_pre_init__(self) -> None: value = "false" if to_bool(value) else "true" elif env_var.endswith("SIMULATION_RUNS"): value = "true" if to_bool(value) else "false" - os.environ[f"BAYBE_{(fld.alias or fld.name).upper()}"] = value + os.environ[f"BAYBE_{name.upper()}"] = value # <<<<< Deprecation known_env_vars = { diff --git a/pyproject.toml b/pyproject.toml index dcd99f2808..e5a21e70c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ keywords = [ ] dynamic = ['version'] dependencies = [ - "attrs>=25.4.0", + "attrs>=26.1.0", "botorch>=0.13.0,<1", "cattrs>=25.2.0", "exceptiongroup", diff --git a/uv.lock b/uv.lock index 7225636aea..55018fb93b 100644 --- a/uv.lock +++ b/uv.lock @@ -157,11 +157,11 @@ wheels = [ [[package]] name = "attrs" -version = "25.4.0" +version = "26.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, ] [[package]] @@ -394,7 +394,7 @@ test = [ [package.metadata] requires-dist = [ - { name = "attrs", specifier = ">=25.4.0" }, + { name = "attrs", specifier = ">=26.1.0" }, { name = "baybe", extras = ["benchmarking"], marker = "extra == 'dev'" }, { name = "baybe", extras = ["chem"], marker = "extra == 'benchmarking'" }, { name = "baybe", extras = ["chem"], marker = "extra == 'extras'" },