Skip to content

Commit dd24b30

Browse files
0.2.1:
- Allow callbacks for file defaults
1 parent 29fc872 commit dd24b30

File tree

8 files changed

+53
-10
lines changed

8 files changed

+53
-10
lines changed

readme.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ sub.cancel()
152152
```
153153

154154
# Changelog
155+
#### 0.2.1 (25.03.2022)
156+
- Allow callbacks for file defaults
157+
155158
#### 0.2.0 (25.03.2022)
156159
- Switched to new and more flexible API
157160
- File default and config default are now separated
@@ -173,6 +176,5 @@ sub.cancel()
173176
- Use json representation of values to get native yaml data types
174177
- Use enum values instead of enum types
175178

176-
177179
#### 0.0.1 (14.09.2021)
178180
- Initial release

setup.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ def load_req() -> typing.List[str]:
4242
description="Easy application configuration with yaml files",
4343
keywords=[
4444
'yaml',
45-
'openhab',
46-
'habapp',
47-
'home automation'
45+
'configuration',
46+
'pydantic',
47+
'settings',
48+
'config'
4849
],
4950
long_description=long_description,
5051
long_description_content_type="text/markdown",
@@ -55,15 +56,16 @@ def load_req() -> typing.List[str]:
5556
package_dir={'': 'src'},
5657
packages=find_packages('src', exclude=['tests*']),
5758
install_requires=load_req(),
59+
python_requires='>=3.8',
5860
classifiers=[
5961
"Development Status :: 4 - Beta",
6062
"Intended Audience :: Developers",
6163
"License :: OSI Approved :: Apache Software License",
6264
"Natural Language :: English",
6365
"Operating System :: OS Independent",
64-
"Programming Language :: Python :: 3.7",
6566
"Programming Language :: Python :: 3.8",
6667
"Programming Language :: Python :: 3.9",
68+
"Programming Language :: Python :: 3.10",
6769
"Programming Language :: Python :: 3 :: Only",
6870
"Topic :: Software Development :: Libraries"
6971
],

src/easyconfig/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.2.0'
1+
__version__ = '0.2.1'

src/easyconfig/config_objs/app_config.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
from inspect import isfunction
12
from pathlib import Path
2-
from typing import Any, Dict, Optional, Tuple, TypeVar, Union
3+
from typing import Any, Callable, Dict, Optional, Tuple, TypeVar, Union
34

45
from pydantic import BaseModel, Extra
56
from typing_extensions import Self
67

78
from easyconfig.__const__ import MISSING, MISSING_TYPE
8-
from .object_config import ConfigObj
99
from easyconfig.yaml import cmap_from_model, CommentedMap, write_aligned_yaml, yaml_rt
1010

11+
from .object_config import ConfigObj
12+
1113

1214
class AppConfig(ConfigObj):
1315
def __init__(self, model: BaseModel, path: Tuple[str, ...] = ('__root__',),
@@ -59,13 +61,18 @@ def load_config_file(self, path: Union[Path, str] = None):
5961

6062

6163
def create_app_config(model: TYPE_WRAPPED,
62-
file_values: Union[MISSING_TYPE, None, BaseModel, Dict[str, Any]] = MISSING,
64+
file_values: Union[MISSING_TYPE, None, BaseModel, Dict[str, Any],
65+
Callable[[], Union[BaseModel, Dict[str, Any]]]] = MISSING,
6366
validate_file_values=True) -> TYPE_WRAPPED:
6467

6568
# Implicit default
6669
if file_values is MISSING:
6770
file_values = model
6871

72+
# if it's a callback we get the values
73+
if isfunction(file_values):
74+
file_values = file_values()
75+
6976
# Validate default
7077
if file_values is not None:
7178
if isinstance(file_values, dict):

src/easyconfig/config_objs/object_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ def _set_values(self, obj: BaseModel) -> bool:
107107
def __repr__(self):
108108
return f'<{self.__class__.__name__} {".".join(self._obj_path)}>'
109109

110+
def __getattr__(self, item):
111+
# delegate call to model
112+
return getattr(self._last_model, item)
113+
110114
# ------------------------------------------------------------------------------------------------------------------
111115
# Match class signature with the Mixin Classes
112116
# ------------------------------------------------------------------------------------------------------------------

tests/test_config_objs/test_app_creation.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,17 @@ class SimpleModel(BaseModel):
1313

1414
with pytest.raises(ValidationError):
1515
create_app_config(SimpleModel(), {'aaaa': 'asdf'})
16+
17+
18+
def test_callback():
19+
class SimpleModel(BaseModel):
20+
a: int = Field(5, alias='aaa')
21+
22+
def get_default():
23+
return SimpleModel(aaa=999)
24+
25+
a = create_app_config(SimpleModel(), get_default)
26+
assert a._file_defaults.a == 999
27+
28+
a = create_app_config(SimpleModel(), lambda: {'aaa': 999})
29+
assert a._file_defaults.a == 999

tests/test_config_objs/test_config_obj.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,18 @@ class SimpleModel(BaseModel):
3232
o.from_orm()
3333

3434
assert str(e.value) == 'Call "load_config_dict" or "load_config_file" on the app config instance!'
35+
36+
37+
def test_attr_access():
38+
test_list = []
39+
40+
class SimpleModel(BaseModel):
41+
a: int = 5
42+
43+
def append(self):
44+
test_list.append(True)
45+
46+
o = ConfigObj.from_model(SimpleModel())
47+
o.append()
48+
49+
assert test_list == [True]

tests/test_pydantic/test_field_access.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ class UserModel(MyModel):
2626

2727

2828
def test_get_model_desc():
29-
3029
assert list(UserModel.__fields__.keys()) == ['val_int', 'val_f', 'val_str', ]
3130

3231
for field in UserModel.__fields__.values():

0 commit comments

Comments
 (0)