Skip to content
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

refactor: change pydantic dataclass decorator #2557

Merged
merged 51 commits into from Aug 4, 2022

Conversation

PrettyWood
Copy link
Member

@PrettyWood PrettyWood commented Mar 21, 2021

Change Summary

Now this is doable

from dataclasses import dataclass as stdlib_dataclass

from pydantic.dataclasses import dataclass as validated_dataclass


@stdlib_dataclass(frozen=True)
class Item:
    name: str
    b: int


ValidatedItem = validated_dataclass(Item)


item = Item(name='qwe', b=1)
item_b = Item(name='qwe', b=b'1')

item_2 = ValidatedItem(name='qwe', b=1)
item_b2 = ValidatedItem(name='qwe', b=b'1')

assert item != item_b
assert item == item_2 == item_b2

assert hash(item) != hash(item_b)
assert hash(item) == hash(item_2) == hash(item_b2)

assert item_b == ValidatedItem(name='qwe', b=b'1', __pydantic_run_validation__=False)

Related issue number

A bunch on stdlib dataclass to validated dataclass
closes #2162
closes #2383
closes #2398
closes #2424
closes #2541
closes #2555
closes #2594
closes #2511
closes #3011
closes #3046
closes #3109
closes #3162
closes #3709

Checklist

  • Unit tests for the changes exist
  • Tests pass on CI and coverage remains at 100%
  • Documentation reflects the changes where applicable
  • changes/<pull request or issue id>-<github username>.md file added describing change
    (see changes/README.md for details)

@samuelcolvin
Copy link
Member

Looks interesting, why dataclasses2? Also, how much has changed from the pydantic.dataclasses module?

@PrettyWood PrettyWood force-pushed the refactor/dataclass-decorator branch 2 times, most recently from c97fd82 to feeee81 Compare March 27, 2021 16:16
@PrettyWood PrettyWood force-pushed the refactor/dataclass-decorator branch 2 times, most recently from 0acde5b to 374f2df Compare March 28, 2021 23:01
@PrettyWood
Copy link
Member Author

PrettyWood commented Mar 28, 2021

@samuelcolvin I added dataclasses2 just to showcase the new proposal of implementation.


So I'm pretty happy with the current state of this PR
I added tests for all the linked issues and some more 🤯

The chosen behaviour is

import dataclasses
import pydantic

@pydantic.dataclasses.dataclass
class M1:
    x: int

@pydantic.dataclasses.dataclass
@dataclasses.dataclass
class M2:
    x: int

@dataclasses.dataclass
class M3:
    x: int

VM3 = pydantic.dataclasses.dataclass(M3)

assert M1(x='3').x == 3
assert M2(x='3').x == 3
assert M3(x='3').x == '3'
assert VM3(x='3').x == 3
assert M3(x=3) == VM3(x=3)

The only issue is for the 3rd case, which should be quite rare!
To do that I added a proxy (taken from the great wrapt library). But to work properly we need the proxy to forward inheritance, which is done thanks to __mro_entries__ available since....3.7! 😓

For python 3.6 we hence tolerate a degraded behaviour with a side effect on the stdlib dataclass: it now triggers validation by default. But it can be changed directly in the validator on thanks to a magic kwarg in __init__. The user is naturally notified with a UserWarning!
(It will give even more reasons for people to move to a more recent python version 😆)

@samuelcolvin I wait for your remarks before updating the documentation. It's quite heavy sorry for that!

@antonl
Copy link

antonl commented Mar 29, 2021

@PrettyWood another testcase to add to your branch #2594

@DetachHead
Copy link
Contributor

when using Extra.allow the extra properties don't show up in __str__

from pydantic import Extra
from pydantic.dataclasses import dataclass


class Config:
    extra = Extra.allow


@dataclass(config=Config)
class Foo:
    a: int


foo = Foo(a=1, b=2)

print(foo.b) # 2
print(foo) # Foo(a=1)

@ahirner
Copy link
Contributor

ahirner commented May 15, 2022

when using Extra.allow the extra properties don't show up in __str__

@DetachHead This caveat is documented in 5907f82

@DetachHead
Copy link
Contributor

is there an issue tracking it? if not i can make one

@haf
Copy link

haf commented May 18, 2022

Can we please merge this and cut a release? :)

@agronick
Copy link

@samuelcolvin @ahirner @robons any update on this?

@samuelcolvin
Copy link
Member

Sorry, been busy with pydantic-core, I'll work on 1.10 soon and this will be included.

@PrettyWood what do you think?

@PrettyWood
Copy link
Member Author

@samuelcolvin taking some days off after a very busy Q2! If you can resolve conflicts, I reckon it's solving a lot of issues with dataclasses. And we'll probably have cleaner logic (and hence code) in v2

@samuelcolvin
Copy link
Member

samuelcolvin commented Aug 4, 2022

This is now just conflicting with #3713, I'm not sure why, I thought I sorted it. Any suggestions? Otherwise I'll dig deeper.

@samuelcolvin samuelcolvin merged commit 576e4a3 into pydantic:master Aug 4, 2022
@samuelcolvin
Copy link
Member

Thank you so much @PrettyWood 🎉, closing 10 issues with one PR must be a record.

Sorry everyone for the delay on this.

@PoojaAg18
Copy link

PoojaAg18 commented Sep 7, 2022

ValidatedItem(name='qwe', b=b'1', pydantic_run_validation=False). using pydantic_run_validation doesn't seems to skip validation. I am using pydantic -1.10.2 @samuelcolvin @PrettyWood

I have created a issue for this - #4496

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment