mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
Allow to configure models through class kwargs (#2356)
* add support for class kwargs config * reformat tests * add changes file and docs * fix linting in 'inherit_config' * tweak docs Co-authored-by: Samuel Colvin <s@muelcolvin.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Allow configuring models through class kwargs
|
||||
@@ -0,0 +1,11 @@
|
||||
from pydantic import BaseModel, ValidationError, Extra
|
||||
|
||||
|
||||
class Model(BaseModel, extra=Extra.forbid):
|
||||
a: str
|
||||
|
||||
|
||||
try:
|
||||
Model(a='spam', b='oh no')
|
||||
except ValidationError as e:
|
||||
print(e)
|
||||
@@ -89,8 +89,13 @@ not be included in the model schemas. **Note**: this means that attributes on th
|
||||
```
|
||||
_(This script is complete, it should run "as is")_
|
||||
|
||||
Similarly, if using the `@dataclass` decorator:
|
||||
Also, you can specify config options as model class kwargs:
|
||||
```py
|
||||
{!.tmp_examples/model_config_class_kwargs.py!}
|
||||
```
|
||||
_(This script is complete, it should run "as is")_
|
||||
|
||||
Similarly, if using the `@dataclass` decorator:
|
||||
```py
|
||||
{!.tmp_examples/model_config_dataclass.py!}
|
||||
```
|
||||
|
||||
+14
-9
@@ -168,18 +168,18 @@ class BaseConfig:
|
||||
pass
|
||||
|
||||
|
||||
def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType') -> 'ConfigType':
|
||||
namespace = {}
|
||||
def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType', **namespace: Any) -> 'ConfigType':
|
||||
if not self_config:
|
||||
base_classes = (parent_config,)
|
||||
base_classes: Tuple['ConfigType', ...] = (parent_config,)
|
||||
elif self_config == parent_config:
|
||||
base_classes = (self_config,)
|
||||
else:
|
||||
base_classes = self_config, parent_config # type: ignore
|
||||
namespace['json_encoders'] = {
|
||||
**getattr(parent_config, 'json_encoders', {}),
|
||||
**getattr(self_config, 'json_encoders', {}),
|
||||
}
|
||||
base_classes = self_config, parent_config
|
||||
|
||||
namespace['json_encoders'] = {
|
||||
**getattr(parent_config, 'json_encoders', {}),
|
||||
**getattr(self_config, 'json_encoders', {}),
|
||||
}
|
||||
|
||||
return type('Config', base_classes, namespace)
|
||||
|
||||
@@ -251,7 +251,12 @@ class ModelMetaclass(ABCMeta):
|
||||
private_attributes.update(base.__private_attributes__)
|
||||
class_vars.update(base.__class_vars__)
|
||||
|
||||
config = inherit_config(namespace.get('Config'), config)
|
||||
config_kwargs = {key: kwargs.pop(key) for key in kwargs.keys() & BaseConfig.__dict__.keys()}
|
||||
config_from_namespace = namespace.get('Config')
|
||||
if config_kwargs and config_from_namespace:
|
||||
raise TypeError('Specifying config in two places is ambiguous, use either Config attribute or class kwargs')
|
||||
config = inherit_config(config_from_namespace, config, **config_kwargs)
|
||||
|
||||
validators = inherit_validators(extract_validators(namespace), validators)
|
||||
vg = ValidatorGroup(validators)
|
||||
|
||||
|
||||
@@ -1550,3 +1550,32 @@ def test_inherited_model_field_untouched():
|
||||
|
||||
assert id(image_1) == id(item.images[0])
|
||||
assert id(image_2) == id(item.images[1])
|
||||
|
||||
|
||||
def test_class_kwargs_config():
|
||||
class Base(BaseModel, extra='forbid', alias_generator=str.upper):
|
||||
a: int
|
||||
|
||||
assert Base.__config__.extra is Extra.forbid
|
||||
assert Base.__config__.alias_generator is str.upper
|
||||
assert Base.__fields__['a'].alias == 'A'
|
||||
|
||||
class Model(Base, extra='allow'):
|
||||
b: int
|
||||
|
||||
assert Model.__config__.extra is Extra.allow # overwritten as intended
|
||||
assert Model.__config__.alias_generator is str.upper # inherited as intended
|
||||
assert Model.__fields__['b'].alias == 'B' # alias_generator still works
|
||||
|
||||
|
||||
def test_class_kwargs_config_and_attr_conflict():
|
||||
|
||||
with pytest.raises(
|
||||
TypeError, match='Specifying config in two places is ambiguous, use either Config attribute or class kwargs'
|
||||
):
|
||||
|
||||
class Model(BaseModel, extra='allow'):
|
||||
b: int
|
||||
|
||||
class Config:
|
||||
extra = 'forbid'
|
||||
|
||||
Reference in New Issue
Block a user