envier
Advanced tools
| from envier.env import Env | ||
| from envier.env import HelpInfo | ||
| En = Env | ||
| __all__ = ["En", "Env"] | ||
| __all__ = ["En", "Env", "HelpInfo"] |
@@ -15,3 +15,3 @@ # file generated by setuptools_scm | ||
| __version__ = version = '0.5.2' | ||
| __version_tuple__ = version_tuple = (0, 5, 2) | ||
| __version__ = version = '0.6.0' | ||
| __version_tuple__ = version_tuple = (0, 6, 0) |
+89
-40
@@ -0,1 +1,3 @@ | ||
| from collections import deque | ||
| from collections import namedtuple | ||
| import os | ||
@@ -20,3 +22,3 @@ import typing as t | ||
| MapType = t.Union[t.Callable[[str], V], t.Callable[[str, str], t.Tuple[K, V]]] | ||
| HelpInfo = t.Tuple[str, str, str, str] | ||
| HelpInfo = namedtuple("HelpInfo", ("name", "type", "default", "help")) | ||
@@ -71,2 +73,8 @@ | ||
| self._full_name = _normalized(name) # Will be set by the EnvMeta metaclass | ||
| @property | ||
| def full_name(self) -> str: | ||
| return f"_{self._full_name}" if self.private else self._full_name | ||
| def _cast(self, _type: t.Any, raw: str, env: "Env") -> t.Any: | ||
@@ -104,5 +112,3 @@ if _type is bool: | ||
| full_name = prefix + _normalized(self.name) | ||
| if self.private: | ||
| full_name = f"_{full_name}" | ||
| full_name = self.full_name | ||
| raw = source.get(full_name.format(**env.dynamic)) | ||
@@ -172,6 +178,4 @@ if raw is None and self.deprecations: | ||
| except ValueError as e: | ||
| full_name = prefix + _normalized(self.name) | ||
| raise ValueError( | ||
| "Invalid value for environment variable %s: %s" % (full_name, e) | ||
| ) | ||
| msg = f"Invalid value for environment variable {self.full_name}: {e}" | ||
| raise ValueError(msg) | ||
@@ -197,3 +201,18 @@ return value | ||
| class Env(object): | ||
| class EnvMeta(type): | ||
| def __new__( | ||
| cls, name: str, bases: t.Tuple[t.Type], ns: t.Dict[str, t.Any] | ||
| ) -> t.Any: | ||
| env = t.cast("Env", super().__new__(cls, name, bases, ns)) | ||
| prefix = ns.get("__prefix__") | ||
| if prefix: | ||
| for v in env.values(recursive=True): | ||
| if isinstance(v, EnvVariable): | ||
| v._full_name = f"{_normalized(prefix)}_{v._full_name}".upper() | ||
| return env | ||
| class Env(metaclass=EnvMeta): | ||
| """Env base class. | ||
@@ -343,24 +362,40 @@ | ||
| @classmethod | ||
| def keys(cls) -> t.Iterator[str]: | ||
| """Return the names of all the items.""" | ||
| return ( | ||
| k | ||
| for k, v in cls.__dict__.items() | ||
| if isinstance(v, (EnvVariable, DerivedVariable)) | ||
| or isinstance(v, type) | ||
| and issubclass(v, Env) | ||
| ) | ||
| def items( | ||
| cls, recursive: bool = False, include_derived: bool = False | ||
| ) -> t.Iterator[t.Tuple[str, t.Union[EnvVariable, DerivedVariable]]]: | ||
| classes = (EnvVariable, DerivedVariable) if include_derived else (EnvVariable,) | ||
| q: t.Deque[t.Tuple[t.Tuple[str], t.Type["Env"]]] = deque() | ||
| path: t.Tuple[str] = tuple() # type: ignore[assignment] | ||
| q.append((path, cls)) | ||
| while q: | ||
| path, env = q.popleft() | ||
| for k, v in env.__dict__.items(): | ||
| if isinstance(v, classes): | ||
| yield ( | ||
| ".".join((*path, k)), | ||
| t.cast(t.Union[EnvVariable, DerivedVariable], v), | ||
| ) | ||
| elif isinstance(v, type) and issubclass(v, Env) and recursive: | ||
| item_name = getattr(v, "__item__", k) | ||
| if item_name is None: | ||
| item_name = k | ||
| q.append(((*path, item_name), v)) # type: ignore[arg-type] | ||
| @classmethod | ||
| def values(cls) -> t.Iterator[t.Union[EnvVariable, DerivedVariable, t.Type["Env"]]]: | ||
| """Return the names of all the items.""" | ||
| return ( | ||
| v | ||
| for v in cls.__dict__.values() | ||
| if isinstance(v, (EnvVariable, DerivedVariable)) | ||
| or isinstance(v, type) | ||
| and issubclass(v, Env) | ||
| ) | ||
| def keys( | ||
| cls, recursive: bool = False, include_derived: bool = False | ||
| ) -> t.Iterator[str]: | ||
| """Return the name of all the configuration items.""" | ||
| for k, _ in cls.items(recursive, include_derived): | ||
| yield k | ||
| @classmethod | ||
| def values( | ||
| cls, recursive: bool = False, include_derived: bool = False | ||
| ) -> t.Iterator[t.Union[EnvVariable, DerivedVariable, t.Type["Env"]]]: | ||
| """Return the value of all the configuration items.""" | ||
| for _, v in cls.items(recursive, include_derived): | ||
| yield v | ||
| @classmethod | ||
| def include( | ||
@@ -379,10 +414,2 @@ cls, | ||
| """ | ||
| if namespace is not None: | ||
| if not overwrite and hasattr(cls, namespace): | ||
| raise ValueError("Namespace already in use: {}".format(namespace)) | ||
| setattr(cls, namespace, env_spec) | ||
| return None | ||
| # Pick only the attributes that define variables. | ||
@@ -396,3 +423,2 @@ to_include = { | ||
| } | ||
| if not overwrite: | ||
@@ -403,4 +429,27 @@ overlap = set(cls.__dict__.keys()) & set(to_include.keys()) | ||
| own_prefix = _normalized(getattr(cls, "__prefix__", "")) | ||
| if namespace is not None: | ||
| if not overwrite and hasattr(cls, namespace): | ||
| raise ValueError("Namespace already in use: {}".format(namespace)) | ||
| if getattr(cls, namespace, None) is not env_spec: | ||
| setattr(cls, namespace, env_spec) | ||
| if own_prefix: | ||
| for _, v in to_include.items(): | ||
| if isinstance(v, EnvVariable): | ||
| v._full_name = f"{own_prefix}_{v._full_name}" | ||
| return None | ||
| other_prefix = getattr(env_spec, "__prefix__", "") | ||
| for k, v in to_include.items(): | ||
| setattr(cls, k, v) | ||
| if getattr(cls, k, None) is not v: | ||
| setattr(cls, k, v) | ||
| if isinstance(v, EnvVariable): | ||
| if other_prefix: | ||
| v._full_name = v._full_name[len(other_prefix) + 1 :] # noqa | ||
| if own_prefix: | ||
| v._full_name = f"{own_prefix}_{v._full_name}" | ||
@@ -444,3 +493,3 @@ @classmethod | ||
| try: | ||
| help_type = "``%s``" % v.type.__name__ # type: ignore[attr-defined] | ||
| help_type = v.type.__name__ # type: ignore[attr-defined] | ||
| except AttributeError: | ||
@@ -453,4 +502,4 @@ # typing.t.Union[<type>, NoneType] | ||
| entries.append( | ||
| ( | ||
| f"``{private_prefix}{full_prefix}{_normalized(v.name)}``", | ||
| HelpInfo( | ||
| f"{private_prefix}{full_prefix}{_normalized(v.name)}", | ||
| help_type, # type: ignore[attr-defined] | ||
@@ -457,0 +506,0 @@ ( |
+2
-1
| Metadata-Version: 2.3 | ||
| Name: envier | ||
| Version: 0.5.2 | ||
| Version: 0.6.0 | ||
| Summary: Python application configuration via the environment | ||
@@ -37,2 +37,3 @@ Project-URL: Homepage, https://github.com/DataDog/envier | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Programming Language :: Python :: 3.13 | ||
| Requires-Python: >=3.7 | ||
@@ -39,0 +40,0 @@ Provides-Extra: mypy |
+2
-1
@@ -23,2 +23,3 @@ [build-system] | ||
| "Programming Language :: Python :: 3.12", | ||
| "Programming Language :: Python :: 3.13", | ||
| "License :: OSI Approved :: MIT License", | ||
@@ -80,3 +81,3 @@ ] | ||
| [[tool.hatch.envs.tests.matrix]] | ||
| python = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] | ||
| python = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] | ||
@@ -83,0 +84,0 @@ [tool.hatch.envs.checks] |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
36818
6.99%568
7.98%