I tried to set a private attribute (that cannot be pickled) to my model:
from threading import Lock
from pydantic import BaseModel
class MyModel(BaseModel):
class Config:
underscore_attrs_are_private = True
_lock: Lock = Lock() # This cannot be copied
x = MyModel()
But this produces an error:
Traceback (most recent call last):
File ".../example.py", line 9, in <module>
x = MyModel()
File "pydantic\main.py", line 349, in pydantic.main.BaseModel.__init__
File "pydantic\main.py", line 419, in pydantic.main.BaseModel._init_private_attributes
File "pydantic\fields.py", line 1180, in pydantic.fields.ModelPrivateAttr.get_default
File "pydantic\utils.py", line 657, in pydantic.utils.smart_deepcopy
File "...\lib\copy.py", line 161, in deepcopy
rv = reductor(4)
TypeError: cannot pickle '_thread.lock' object
It seems it fails because Lock cannot be pickled (or copied). Furthermore, it seems Pydantic tries to copy private attributes for some reason. I looked in the docs and could not find a model property to override this. Also, the configs arbitrary_types_allowed or copy_on_model_validation have no effect. I also tried to use PrivateAttr(default=Lock()) but that did not help.
Interestingly, the example works if the attribute was not private (by setting underscore_attrs_are_private = False in Config).
I would like to have this attribute as private. How can I set a private attribute that cannot be pickled to Pydantic Model?
I found the answer myself after doing some more investigation. It seems this can be solved using default_factory:
from threading import Lock
from pydantic import BaseModel, PrivateAttr
class MyModel(BaseModel):
class Config:
underscore_attrs_are_private = True
_lock = PrivateAttr(default_factory=Lock)
x = MyModel()
Furthermore, it seems the copying is done in the BaseModel init only. One can also set the attribute later:
from threading import Lock
from pydantic import BaseModel, PrivateAttr
class MyModel(BaseModel):
class Config:
underscore_attrs_are_private = True
_lock: Lock
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._lock = Lock()
x = MyModel()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With