Usage of frozen attribute in models #12036
Replies: 2 comments · 6 replies
-
|
The solution you were using wasn't meant to be supported, and could lead (before and after 2.10) to a lot of unexpected behavior. You are mutating What is your use case to have models frozen only after validation? |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for the clarification about frozen being a class-level configuration and not intended to be mutated per instance. That makes perfect sense. For our use case—where we need to perform some post-initialization mutations (e.g., normalizing fields, computing derived values) after validation but before the model becomes immutable—we’ve adopted the recommended pattern of using To make this more ergonomic and reusable, we wrapped it into a context manager and a decorator. Here’s a minimal working example: from pydantic import BaseModel, ConfigDict
from functools import wraps
class ForceSetAttr:
"""Context manager to temporarily allow setting attributes on frozen Pydantic models."""
def __init__(self, obj: BaseModel):
if not isinstance(obj, BaseModel):
raise TypeError(
"ForceSetAttr can only be used with Pydantic BaseModel instances."
)
self._obj = obj
def __enter__(self):
self._original_setattr = self._obj.__class__.__setattr__
self._obj.__class__.__setattr__ = self._setattr
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._obj.__class__.__setattr__ = self._original_setattr
def _setattr(self, name, value):
obj = self._obj
config = obj.model_config
if config.get("frozen", False):
if config.get("validate_assignment", False):
obj.__pydantic_validator__.validate_assignment(obj, name, value)
else:
object.__setattr__(obj, name, value)
else:
setattr(obj, name, value)
def force_set_attr(method):
"""Decorator to force attribute setting on frozen Pydantic models."""
@wraps(method)
def wrapper(self, *args, **kwargs):
with ForceSetAttr(self):
return method(self, *args, **kwargs)
return wrapper
class TestModel(BaseModel, frozen=True):
id: int
name: str
value: float
model_config = ConfigDict(validate_assignment=True)
@force_set_attr
def model_post_init(self, context):
self.name = self.name.upper()
self.value = self.value * 2
self.id = 1.0
print(TestModel(id=1, name="example", value=10.0))
# Output: id=1 name='EXAMPLE' value=20.0It is worth mentioning that when both |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Using Pydantic version >2.10.6, the frozen attribute is not working properly. Below is how we have set up the basic model that will be used by all the other models in our project:
But the frozen attribute is being ignored, and changing the attributes of the class works:

I saw that
_check_frozenwas modified, and the frozen attribute is now being checked at the class level, not at the instance level. DetailsDo you have any idea what the problem could be, and do you have any suggestions?
**We want to freeze the model after the initialization is done.
Beta Was this translation helpful? Give feedback.
All reactions