Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow for shallow copies #4093

Merged
merged 13 commits into from Aug 10, 2022
2 changes: 2 additions & 0 deletions changes/4093-timkpaine.md
@@ -0,0 +1,2 @@
Allow for shallow copies of attributes, adjusting the behavior of #3642
`Config.copy_on_model_validation` does a shallow copy and not a deep one if `Config.copy_on_model_validation_shallow` is also `True`.
5 changes: 4 additions & 1 deletion pydantic/config.py
Expand Up @@ -62,8 +62,11 @@ class BaseConfig:
json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable] = {}
underscore_attrs_are_private: bool = False

# whether inherited models as fields should be reconstructed as base model
# whether inherited models as fields should be reconstructed as base model,
# and whether such a copy should be shallow or deep
copy_on_model_validation: bool = True
copy_on_model_validation_shallow: bool = False
timkpaine marked this conversation as resolved.
Show resolved Hide resolved

# whether `Union` should check all allowed types before even trying to coerce
smart_union: bool = False

Expand Down
4 changes: 3 additions & 1 deletion pydantic/main.py
Expand Up @@ -675,7 +675,9 @@ def __get_validators__(cls) -> 'CallableGenerator':
@classmethod
def validate(cls: Type['Model'], value: Any) -> 'Model':
if isinstance(value, cls):
if cls.__config__.copy_on_model_validation:
if cls.__config__.copy_on_model_validation and cls.__config__.copy_on_model_validation_shallow:
return value._copy_and_set_values(value.__dict__, value.__fields_set__, deep=False)
elif cls.__config__.copy_on_model_validation:
return value._copy_and_set_values(value.__dict__, value.__fields_set__, deep=True)
else:
return value
Expand Down
22 changes: 22 additions & 0 deletions tests/test_main.py
Expand Up @@ -1567,6 +1567,28 @@ class Config:
assert t.dict() == {'id': '1234567890', 'user': {'id': 42, 'hobbies': ['scuba diving']}}


def test_model_exclude_copy_on_model_validation_shallow():
"""When `Config.copy_on_model_validation` is set and `Config.copy_on_model_validation_shallow` is set,
do the same as the previous test but perform a shallow copy"""

class User(BaseModel):
class Config:
copy_on_model_validation_shallow = True

hobbies: List[str]

my_user = User(hobbies=['scuba diving'])

class Transaction(BaseModel):
user: User = Field(...)

t = Transaction(
user=my_user,
)

assert t.user.hobbies is my_user.hobbies # unlike above, this should be a shallow copy


def test_validation_deep_copy():
"""By default, Config.copy_on_model_validation should do a deep copy"""

Expand Down