diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 9a1a676775..9d8efcabda 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -3,6 +3,7 @@ import builtins import ipaddress import uuid +import warnings from collections.abc import Callable, Mapping, Sequence, Set from dataclasses import dataclass from datetime import date, datetime, time, timedelta @@ -11,6 +12,7 @@ from pathlib import Path from typing import ( TYPE_CHECKING, + Annotated, Any, ClassVar, Literal, @@ -89,6 +91,8 @@ ) OnDeleteType = Literal["CASCADE", "SET NULL", "RESTRICT"] +INCLUDE_DEPRECATION_MSG = "`include` is deprecated and does nothing. It will be removed, use `exclude` instead" + def __dataclass_transform__( *, @@ -243,8 +247,11 @@ def Field( serialization_alias: str | None = None, title: str | None = None, description: str | None = None, - exclude: Set[int | str] | Mapping[int | str, Any] | Any = None, - include: Set[int | str] | Mapping[int | str, Any] | Any = None, + exclude: bool | None = None, + include: Annotated[ + Set[int | str] | Mapping[int | str, Any] | Any, + deprecated(INCLUDE_DEPRECATION_MSG), + ] = None, const: bool | None = None, gt: float | None = None, ge: float | None = None, @@ -286,8 +293,11 @@ def Field( serialization_alias: str | None = None, title: str | None = None, description: str | None = None, - exclude: Set[int | str] | Mapping[int | str, Any] | Any = None, - include: Set[int | str] | Mapping[int | str, Any] | Any = None, + exclude: bool | None = None, + include: Annotated[ + Set[int | str] | Mapping[int | str, Any] | Any, + deprecated(INCLUDE_DEPRECATION_MSG), + ] = None, const: bool | None = None, gt: float | None = None, ge: float | None = None, @@ -338,8 +348,11 @@ def Field( serialization_alias: str | None = None, title: str | None = None, description: str | None = None, - exclude: Set[int | str] | Mapping[int | str, Any] | Any = None, - include: Set[int | str] | Mapping[int | str, Any] | Any = None, + exclude: bool | None = None, + include: Annotated[ + Set[int | str] | Mapping[int | str, Any] | Any, + deprecated(INCLUDE_DEPRECATION_MSG), + ] = None, const: bool | None = None, gt: float | None = None, ge: float | None = None, @@ -371,8 +384,11 @@ def Field( serialization_alias: str | None = None, title: str | None = None, description: str | None = None, - exclude: Set[int | str] | Mapping[int | str, Any] | Any = None, - include: Set[int | str] | Mapping[int | str, Any] | Any = None, + exclude: bool | None = None, + include: Annotated[ + Set[int | str] | Mapping[int | str, Any] | Any, + deprecated(INCLUDE_DEPRECATION_MSG), + ] = None, const: bool | None = None, gt: float | None = None, ge: float | None = None, @@ -403,6 +419,10 @@ def Field( schema_extra: dict[str, Any] | None = None, ) -> Any: current_schema_extra = schema_extra or {} + + if include is not None: + warnings.warn(INCLUDE_DEPRECATION_MSG, DeprecationWarning, stacklevel=2) + # Extract possible alias settings from schema_extra so we can control precedence schema_validation_alias = current_schema_extra.pop("validation_alias", None) schema_serialization_alias = current_schema_extra.pop("serialization_alias", None) diff --git a/tests/test_pydantic/test_field.py b/tests/test_pydantic/test_field.py index 11f4150d98..c07a18cb3b 100644 --- a/tests/test_pydantic/test_field.py +++ b/tests/test_pydantic/test_field.py @@ -54,3 +54,26 @@ class Model(SQLModel): instance = Model(id=123, foo="bar") assert "foo=" not in repr(instance) + + +def test_exclude(): + class Model(SQLModel): + id: int + name: str + value: int = Field(exclude=True) + + instance = Model(id=1, name="test", value=42) + dict_representation = instance.model_dump() + assert "id" in dict_representation + assert "name" in dict_representation + assert "value" not in dict_representation + + +def test_include_is_deprecated(): + with pytest.warns( + DeprecationWarning, + match="`include` is deprecated and does nothing. It will be removed, use `exclude` instead", + ): + + class Model(SQLModel): + values: list[int] = Field(include=True)