Merge pull request #712 from MrMrRobat/__dict__-instead-of-__values__

Rename BaseModel.__values__ to  BaseModel.__dict__
This commit is contained in:
Samuel Colvin
2019-08-05 11:48:09 +01:00
committed by GitHub
3 changed files with 43 additions and 27 deletions
+2 -1
View File
@@ -3,10 +3,11 @@
History
-------
v0.32 (unreleased)
..................
* add model name to ``ValidationError`` error message, #676 by @dmontagu
* **breaking change**: remove ``__getattr__`` and rename ``__values__`` to ``__dict__`` on ``BaseModel``,
deprecation warning on use ``__values__`` attr, attributes access speed increased up to 14 times, #712 by @MrMrRobat
v0.31.1 (2019-07-31)
....................
+19 -26
View File
@@ -266,24 +266,17 @@ class BaseModel(metaclass=MetaModel):
_custom_root_type: bool = False
Config = BaseConfig
__slots__ = ('__values__', '__fields_set__')
__slots__ = ('__dict__', '__fields_set__')
def __init__(__pydantic_self__, **data: Any) -> None:
# Uses something other than `self` the first arg to allow "self" as a settable attribute
if TYPE_CHECKING: # pragma: no cover
__pydantic_self__.__values__: Dict[str, Any] = {}
__pydantic_self__.__dict__: Dict[str, Any] = {}
__pydantic_self__.__fields_set__: 'SetStr' = set()
values, fields_set, _ = validate_model(__pydantic_self__, data)
object.__setattr__(__pydantic_self__, '__values__', values)
object.__setattr__(__pydantic_self__, '__dict__', values)
object.__setattr__(__pydantic_self__, '__fields_set__', fields_set)
@no_type_check
def __getattr__(self, name):
try:
return self.__values__[name]
except KeyError:
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
@no_type_check
def __setattr__(self, name, value):
if self.__config__.extra is not Extra.allow and name not in self.__fields__:
@@ -295,17 +288,17 @@ class BaseModel(metaclass=MetaModel):
if error_:
raise ValidationError([error_], type(self))
else:
self.__values__[name] = value_
self.__dict__[name] = value_
self.__fields_set__.add(name)
else:
self.__values__[name] = value
self.__dict__[name] = value
self.__fields_set__.add(name)
def __getstate__(self) -> 'DictAny':
return {'__values__': self.__values__, '__fields_set__': self.__fields_set__}
return {'__dict__': self.__dict__, '__fields_set__': self.__fields_set__}
def __setstate__(self, state: 'DictAny') -> None:
object.__setattr__(self, '__values__', state['__values__'])
object.__setattr__(self, '__dict__', state['__dict__'])
object.__setattr__(self, '__fields_set__', state['__fields_set__'])
def dict(
@@ -413,18 +406,18 @@ class BaseModel(metaclass=MetaModel):
obj = cls._decompose_class(obj)
m = cls.__new__(cls)
values, fields_set, _ = validate_model(m, obj)
object.__setattr__(m, '__values__', values)
object.__setattr__(m, '__dict__', values)
object.__setattr__(m, '__fields_set__', fields_set)
return m
@classmethod
def construct(cls: Type['Model'], values: 'DictAny', fields_set: 'SetStr') -> 'Model':
"""
Creates a new model and set __values__ without any validation, thus values should already be trusted.
Creates a new model and set __dict__ without any validation, thus values should already be trusted.
Chances are you don't want to use this method directly.
"""
m = cls.__new__(cls)
object.__setattr__(m, '__values__', values)
object.__setattr__(m, '__dict__', values)
object.__setattr__(m, '__fields_set__', fields_set)
return m
@@ -448,11 +441,11 @@ class BaseModel(metaclass=MetaModel):
"""
if include is None and exclude is None and update is None:
# skip constructing values if no arguments are passed
v = self.__values__
v = self.__dict__
else:
allowed_keys = self._calculate_keys(include=include, exclude=exclude, skip_defaults=False, update=update)
if allowed_keys is None:
v = {**self.__values__, **(update or {})}
v = {**self.__dict__, **(update or {})}
else:
v = {
**dict(
@@ -595,7 +588,7 @@ class BaseModel(metaclass=MetaModel):
value_exclude = ValueItems(self, exclude) if exclude else None
value_include = ValueItems(self, include) if include else None
for k, v in self.__values__.items():
for k, v in self.__dict__.items():
if allowed_keys is None or k in allowed_keys:
yield k, self._get_value(
v,
@@ -619,7 +612,7 @@ class BaseModel(metaclass=MetaModel):
if skip_defaults:
keys = self.__fields_set__.copy()
else:
keys = set(self.__values__.keys())
keys = set(self.__dict__.keys())
if include is not None:
if isinstance(include, dict):
@@ -652,16 +645,16 @@ class BaseModel(metaclass=MetaModel):
return '{}{}{}'.format(
self.__class__.__name__,
divider,
divider.join('{}={}'.format(k, truncate(v)) for k, v in self.__values__.items()),
divider.join('{}={}'.format(k, truncate(v)) for k, v in self.__dict__.items()),
)
def __str__(self) -> str:
return self.to_string()
def __dir__(self) -> 'ListStr':
ret = list(object.__dir__(self))
ret.extend(self.__values__.keys())
return ret
@property
def __values__(self) -> 'DictStrAny':
warnings.warn('`__values__` attribute is deprecated, use `__dict__` instead', DeprecationWarning)
return self.__dict__
def create_model(
+22
View File
@@ -995,3 +995,25 @@ def test_nested_init(model):
assert m.self == 'Top Model'
assert m.nest.self == 'Nested Model'
assert m.nest.modified_number == 1
def test_values_attr_deprecation():
class Model(BaseModel):
foo: int
bar: str
m = Model(foo=4, bar='baz')
with pytest.warns(DeprecationWarning, match='`__values__` attribute is deprecated, use `__dict__` instead'):
assert m.__values__ == m.__dict__
def test_init_inspection():
class Foobar(BaseModel):
x: int
def __init__(self, **data) -> None:
with pytest.raises(AttributeError):
assert self.x
super().__init__(**data)
Foobar(x=1)