Skip to content

Commit 05a421d

Browse files
committed
Fix Pydantic rebinding self in model constraint validator
1 parent 8f1a463 commit 05a421d

1 file changed

Lines changed: 10 additions & 5 deletions

File tree

packages/overture-schema-system/src/overture/schema/system/model_constraint/model_constraint.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ def __init__(self, name: str | None = None):
5656
)
5757
self.__name = name
5858

59-
def __validate_instance(self, model_instance: BaseModel) -> BaseModel:
60-
self.validate_instance(model_instance)
61-
return model_instance
62-
6359
@property
6460
def name(self) -> str:
6561
"""Returns the name of the constraint, e.g. "FooConstraint" or "@foo"."""
@@ -126,6 +122,15 @@ def decorate(self, model_class: type[BaseModel]) -> type[BaseModel]:
126122
metadata = Metadata.retrieve_from(model_class, Metadata()).copy() # type: ignore[union-attr]
127123
model_constraints = (*ModelConstraint.get_model_constraints(model_class), self)
128124
metadata[_MODEL_CONSTRAINT_KEY] = model_constraints
125+
# Capture the constraint in a closure rather than passing a bound method.
126+
# Some Pydantic versions unwrap bound methods passed through __validators__
127+
# and rebind `self` to the model instance, breaking the dispatch.
128+
constraint = self
129+
130+
def _after_validator(model_instance: BaseModel) -> BaseModel:
131+
constraint.validate_instance(model_instance)
132+
return model_instance
133+
129134
new_model_class = create_model(
130135
model_class.__name__,
131136
__config__=config,
@@ -135,7 +140,7 @@ def decorate(self, model_class: type[BaseModel]) -> type[BaseModel]:
135140
__validators__={
136141
self.name: cast(
137142
Callable[..., Any],
138-
model_validator(mode="after")(self.__validate_instance),
143+
model_validator(mode="after")(_after_validator),
139144
)
140145
},
141146
__metadata__=metadata,

0 commit comments

Comments
 (0)