Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion packages/testing/src/execution_testing/base_types/pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,38 @@ class CopyValidateModel(EthereumTestBaseModel):
def copy(self: Self, **kwargs: Any) -> Self:
"""
Create a copy of the model with the updated fields that are validated.

This method preserves the actual field values (including those set via
default_factory) while maintaining the model_fields_set to track which
fields were explicitly set.

The implementation uses exclude_unset=True as a safe baseline, then
explicitly adds back fields that were set via default_factory but not
explicitly set by the user. This avoids conflicts with models that have
mutually exclusive fields (e.g., Transaction with secret_key vs signature).
"""
return self.__class__(**(self.model_dump(exclude_unset=True) | kwargs))
# Start with explicitly set fields (safe baseline)
dump_dict = self.model_dump(exclude_unset=True)

# For fields with default_factory, include them if they're not in model_fields_set
# This handles cases like Environment.gas_limit where the factory captures
# dynamic configuration that should be preserved in copies
for field_name, field_info in self.__class__.model_fields.items():
if (
field_name not in self.model_fields_set
and field_info.default_factory
):
dump_dict[field_name] = getattr(self, field_name)

# Merge with the updates
dump_dict.update(kwargs)
# Create the new instance
new_instance = self.__class__(**dump_dict)
# Preserve the original model_fields_set, adding any new kwargs
new_instance.__pydantic_fields_set__ = (
self.model_fields_set | kwargs.keys()
)
return new_instance


class CamelModel(CopyValidateModel):
Expand Down
Loading