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
modify behaviour of the construct method #898
Conversation
Codecov Report
@@ Coverage Diff @@
## master #898 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 16 16
Lines 2799 2799
Branches 543 543
=====================================
Hits 2799 2799 Continue to review full report at Codecov.
|
This is very close to what I want. A few points:
|
To be more explicit, I think a method like this would be easier to make type-safe (here, I'm using the "old" version of @classmethod
def safe_construct(cls: Type[Model], **data: Any) -> Model:
# TODO: Cache defaults
defaults = {name: deepcopy(field.default) for name, field in cls.__fields__.items() if not field.required}
values = {**defaults, **data}
fields_set = set(data.keys())
return cls.construct(values, fields_set) |
@dmontagu I'm fine with that, the only reason I didn't do that was that I thought it avoided the possibility to provide E.g. you do something like: model_data = dict(model1)
...
# lots of process, RPC etc.
...
model2 = Model.construct(model_data) But obviously So I was allowing for model_data = dict(model1)
model_fields_set = model1.__fields_set__
...
# lots of process, RPC etc.
...
model2 = Model.construct(model_data, model_fields_set) I know this won't be used much, but it should be possible. However I think we can have the best of both worlds: since we have to trust the input data to So the signature of construct becomes something like: def construct(cls: Type[Model], *, _fields_set: Optional['SetStr'] = None, **model_data: Any) -> Model: Would this work for you? Regarding caching |
Starting with the |
I did the profiling -- I get about a 30x speedup with this implementation over the with-validation-approach in my benchmarking script. I get about a 36x speedup if I cache the default values. But not caching removes a nuisance around mutable default values: we'd have to worry about deepcopying the cached values (I wasn't doing that when getting the 36x). Given the "slow" version still offers a 30x speed improvement, and this method seems somewhat rarely used now, I'm happy with this (more maintainable) version. If this method starts getting heavier use, and if further performance improvements to it become a priority, we could always revisit. +1 for merging as it is now implemented |
@@ -414,14 +414,17 @@ def from_orm(cls: Type['Model'], obj: Any) -> 'Model': | |||
return m | |||
|
|||
@classmethod | |||
def construct(cls: Type['Model'], values: 'DictAny', fields_set: 'SetStr') -> 'Model': | |||
def construct(cls: Type['Model'], _fields_set: Optional['SetStr'] = None, **values: Any) -> 'Model': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@samuelcolvin Would it make sense to rename cls
to __pydantic_cls__
(similar to in BaseModel.__init__
), or at least something that starts with a _
to prevent keyword argument conflicts?
* add example for construct * edit exporting_models * typo * add changes file * code review changes * fix bad copy paste
pydantic/main.py
Outdated
m = cls.__new__(cls) | ||
object.__setattr__(m, '__dict__', values) | ||
object.__setattr__(m, '__fields_set__', fields_set) | ||
object.__setattr__(m, '__dict__', {**defaults, **values}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can replace defaults
with cls.__defaults__
once #915 is merged; that can be a separate PR though if this is ready first.
I think this is ready, I'll merge it after #915 and the defaults tweak above. |
* modify behaviour of the construct method * change construct signature * Add example for construct function (samuelcolvin#907) * add example for construct * edit exporting_models * typo * add changes file * code review changes * fix bad copy paste * extend example in docs * use __field_defaults__ in construct
Change Summary
Change
construct
, fix #897Checklist
changes/<pull request or issue id>-<github username>.md
file added describing change(see changes/README.md for details)