Skip to content

Conversation

PrettyWood
Copy link
Collaborator

@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
Collaborator 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!

@PrettyWood PrettyWood force-pushed the refactor/dataclass-decorator branch from 374f2df to e1396e4 Compare March 28, 2021 23:15
@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
Collaborator 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