No dict update (#1244)

* update_forward_refs now modifies only a copy of __dict__ of cls.__module__

* changes

* test for update_forward_refs

* fixed brackets

* black changes fixed

* make format

Co-authored-by: Samuel Colvin <s@muelcolvin.com>
This commit is contained in:
Pavel Ilyin
2020-03-17 22:57:13 +03:00
committed by GitHub
parent d1279e865e
commit d8262131d2
5 changed files with 24 additions and 18 deletions
+1
View File
@@ -0,0 +1 @@
`update_forward_refs()` method of BaseModel now copies `__dict__` of class module instead of modyfying it
+1 -1
View File
@@ -646,7 +646,7 @@ class BaseModel(metaclass=ModelMetaclass):
"""
Try to update ForwardRefs on fields based on this Model, globalns and localns.
"""
globalns = sys.modules[cls.__module__].__dict__
globalns = sys.modules[cls.__module__].__dict__.copy()
globalns.setdefault(cls.__name__, cls)
for f in cls.__fields__.values():
update_field_forward_refs(f, globalns=globalns, localns=localns)
+1 -4
View File
@@ -330,10 +330,7 @@ def test_alias_priority():
a: str = Field(..., alias='a_field_child')
class Config:
fields = {
'a': dict(alias='a_config_child'),
'b': dict(alias='b_config_child'),
}
fields = {'a': dict(alias='a_config_child'), 'b': dict(alias='b_config_child')}
@staticmethod
def alias_generator(x):
+10 -12
View File
@@ -35,21 +35,21 @@ def test_args():
foo(1, 'x')
assert exc_info.value.errors() == [
{'loc': ('b',), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'},
{'loc': ('b',), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
]
with pytest.raises(ValidationError) as exc_info:
foo(1, 2, 3)
assert exc_info.value.errors() == [
{'loc': ('args',), 'msg': '2 positional arguments expected but 3 given', 'type': 'type_error'},
{'loc': ('args',), 'msg': '2 positional arguments expected but 3 given', 'type': 'type_error'}
]
with pytest.raises(ValidationError) as exc_info:
foo(1, 2, apple=3)
assert exc_info.value.errors() == [
{'loc': ('kwargs',), 'msg': "unexpected keyword argument: 'apple'", 'type': 'type_error'},
{'loc': ('kwargs',), 'msg': "unexpected keyword argument: 'apple'", 'type': 'type_error'}
]
@@ -87,7 +87,7 @@ def test_kwargs():
foo(a=1, b='x')
assert exc_info.value.errors() == [
{'loc': ('b',), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'},
{'loc': ('b',), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
]
with pytest.raises(ValidationError) as exc_info:
@@ -141,7 +141,7 @@ def foo(a, b, /, c=None):
'loc': ('v__positional_only',),
'msg': "positional-only argument passed as keyword argument: 'b'",
'type': 'type_error',
},
}
]
with pytest.raises(ValidationError) as exc_info:
module.foo(a=1, b=2)
@@ -150,7 +150,7 @@ def foo(a, b, /, c=None):
'loc': ('v__positional_only',),
'msg': "positional-only arguments passed as keyword arguments: 'a', 'b'",
'type': 'type_error',
},
}
]
@@ -165,19 +165,19 @@ def test_args_name():
with pytest.raises(ValidationError) as exc_info:
foo(1, 2, apple=4)
assert exc_info.value.errors() == [
{'loc': ('v__kwargs',), 'msg': "unexpected keyword argument: 'apple'", 'type': 'type_error'},
{'loc': ('v__kwargs',), 'msg': "unexpected keyword argument: 'apple'", 'type': 'type_error'}
]
with pytest.raises(ValidationError) as exc_info:
foo(1, 2, apple=4, banana=5)
assert exc_info.value.errors() == [
{'loc': ('v__kwargs',), 'msg': "unexpected keyword arguments: 'apple', 'banana'", 'type': 'type_error'},
{'loc': ('v__kwargs',), 'msg': "unexpected keyword arguments: 'apple', 'banana'", 'type': 'type_error'}
]
with pytest.raises(ValidationError) as exc_info:
foo(1, 2, 3)
assert exc_info.value.errors() == [
{'loc': ('v__args',), 'msg': '2 positional arguments expected but 3 given', 'type': 'type_error'},
{'loc': ('v__args',), 'msg': '2 positional arguments expected but 3 given', 'type': 'type_error'}
]
@@ -202,9 +202,7 @@ def test_async():
loop.run_until_complete(run())
with pytest.raises(ValidationError) as exc_info:
loop.run_until_complete(foo('x'))
assert exc_info.value.errors() == [
{'loc': ('b',), 'msg': 'field required', 'type': 'value_error.missing'},
]
assert exc_info.value.errors() == [{'loc': ('b',), 'msg': 'field required', 'type': 'value_error.missing'}]
def test_string_annotation():
+11 -1
View File
@@ -1,5 +1,6 @@
import sys
from enum import Enum
from typing import Any, Callable, ClassVar, List, Mapping, Type
from typing import Any, Callable, ClassVar, List, Mapping, Optional, Type
from uuid import UUID, uuid4
import pytest
@@ -995,6 +996,15 @@ def test_custom_init_subclass_params():
assert NewModel.something == 2
def test_update_forward_refs_does_not_modify_module_dict():
class MyModel(BaseModel):
field: Optional['MyModel']
MyModel.update_forward_refs()
assert 'MyModel' not in sys.modules[MyModel.__module__].__dict__
def test_two_defaults():
with pytest.raises(ValueError, match='^cannot specify both default and default_factory$'):