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