Coverage for src/configuraptor/alias.py: 100%
16 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-09 20:07 +0100
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-09 20:07 +0100
1"""
2Alias functionality so config keys can have multiple names.
3"""
5import typing
6from dataclasses import dataclass
7from typing import Any
9from .abs import AnyType, T
12@dataclass(frozen=True, slots=True)
13class Alias:
14 """
15 Internal class used to relate keys.
16 """
18 to: str
21def alias(to: str) -> Any:
22 """
23 Function to create an alias to a different key in the same class.
24 """
25 return Alias(to)
28def has_aliases(cls: AnyType, key: str) -> typing.Generator[str, None, None]:
29 """
30 Generate all aliases that point to 'key' in 'cls'.
31 """
32 for field, value in cls.__dict__.items():
33 if isinstance(value, Alias) and value.to == key:
34 yield field
37def has_alias(cls: AnyType, key: str, data: dict[str, T]) -> typing.Optional[T]:
38 """
39 Get the value of any alias in the same config class that references `key`.
41 Example:
42 class Config:
43 key1: str
44 key2: str = alias('key1')
46 load_into(Config, {'key2': 'something'})
47 # -> key1 will look up the value of key2 because it's configured as an alias for it.
49 If multiple aliases point to the same base, they are all iterated until a valid value was found.
50 """
51 # for field, value in cls.__dict__.items():
52 # if isinstance(value, Alias) and value.to == key:
53 # # yay!
54 # return data.get(field)
55 #
56 # return None
58 return next(
59 (value for field in has_aliases(cls, key) if (value := data.get(field))),
60 None,
61 )
64def is_alias(cls: AnyType, prop: str) -> bool:
65 """
66 Returns whether 'prop' is an alias to something else on cls.
67 """
68 return isinstance(cls.__dict__.get(prop), Alias)