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

Move function is_pydantic_dataclass from pydantic._internal._dataclasses to pydantic.dataclasses #7213

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/usage/dataclasses.md
Expand Up @@ -356,6 +356,34 @@ print(repr(m))
#> Model(dc=DC(a=ArbitraryType(value=3), b='qwe'), other='other')
```

### Checking if a dataclass is a pydantic dataclass

Pydantic dataclasses are still considered dataclasses, so using `dataclasses.is_dataclass` will return `True`. To check if a type is specifically a pydantic dataclass you can use `pydantic.dataclasses.is_pydantic_dataclass`.

```py
import dataclasses

import pydantic


@dataclasses.dataclass
class StdLibDataclass:
id: int


PydanticDataclass = pydantic.dataclasses.dataclass(StdLibDataclass)

print(dataclasses.is_dataclass(StdLibDataclass))
#> True
print(pydantic.dataclasses.is_pydantic_dataclass(StdLibDataclass))
#> False

print(dataclasses.is_dataclass(PydanticDataclass))
#> True
print(pydantic.dataclasses.is_pydantic_dataclass(PydanticDataclass))
#> True
```

## Initialization hooks

When you initialize a dataclass, it is possible to execute code *before* or *after* validation
Expand Down
12 changes: 0 additions & 12 deletions pydantic/_internal/_dataclasses.py
Expand Up @@ -259,15 +259,3 @@ class B(A):
and not hasattr(_cls, '__pydantic_validator__')
and set(_cls.__dataclass_fields__).issuperset(set(getattr(_cls, '__annotations__', {})))
)


def is_pydantic_dataclass(_cls: type[Any]) -> TypeGuard[type[PydanticDataclass]]:
"""Whether a class is a pydantic dataclass.

Args:
cls: The class.

Returns:
`True` if the class is a pydantic dataclass, `False` otherwise.
"""
return dataclasses.is_dataclass(_cls) and '__pydantic_validator__' in _cls.__dict__
2 changes: 1 addition & 1 deletion pydantic/_internal/_generate_schema.py
Expand Up @@ -1308,7 +1308,7 @@ def _dataclass_schema(

self = self._current_generate_schema

from ._dataclasses import is_pydantic_dataclass
from ..dataclasses import is_pydantic_dataclass

if is_pydantic_dataclass(dataclass):
fields = dataclass.__pydantic_fields__
Expand Down
14 changes: 13 additions & 1 deletion pydantic/dataclasses.py
Expand Up @@ -6,7 +6,7 @@
import types
from typing import TYPE_CHECKING, Any, Callable, Generic, NoReturn, TypeVar, overload

from typing_extensions import Literal, dataclass_transform
from typing_extensions import Literal, TypeGuard, dataclass_transform

from ._internal import _config, _decorators, _typing_extra
from ._internal import _dataclasses as _pydantic_dataclasses
Expand Down Expand Up @@ -276,3 +276,15 @@ def rebuild_dataclass(
raise_errors=raise_errors,
types_namespace=types_namespace,
)


def is_pydantic_dataclass(_cls: type[Any]) -> TypeGuard[type[PydanticDataclass]]:
"""Whether a class is a pydantic dataclass.

Args:
_cls: The class.
adriangb marked this conversation as resolved.
Show resolved Hide resolved

Returns:
`True` if the class is a pydantic dataclass, `False` otherwise.
"""
return dataclasses.is_dataclass(_cls) and '__pydantic_validator__' in _cls.__dict__
adriangb marked this conversation as resolved.
Show resolved Hide resolved
15 changes: 14 additions & 1 deletion tests/test_dataclasses.py
Expand Up @@ -33,7 +33,7 @@
model_validator,
)
from pydantic._internal._mock_validator import MockValidator
from pydantic.dataclasses import rebuild_dataclass
from pydantic.dataclasses import is_pydantic_dataclass, rebuild_dataclass
from pydantic.fields import Field, FieldInfo
from pydantic.json_schema import model_json_schema

Expand Down Expand Up @@ -2487,3 +2487,16 @@ class A:
assert count == 0
TypeAdapter(A).validate_python({'a': 123})
assert count == 1


def test_is_pydantic_dataclass():
@pydantic.dataclasses.dataclass
class PydanticDataclass:
a: int

@dataclasses.dataclass
class StdLibDataclass:
b: int

assert is_pydantic_dataclass(PydanticDataclass) is True
assert is_pydantic_dataclass(StdLibDataclass) is False