Skip to content

Commit

Permalink
Some initial PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
Viicos committed Dec 12, 2023
1 parent d7a074b commit b233059
Show file tree
Hide file tree
Showing 9 changed files with 581 additions and 170 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Expand Up @@ -312,7 +312,7 @@ jobs:
fail-fast: false
matrix:
# test the oldest supported version and main
typing-extensions-version: ['4.9.0', 'main']
typing-extensions-version: ['4.6.1', 'main']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

steps:
Expand Down
689 changes: 557 additions & 132 deletions pdm.lock

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions pydantic/_internal/_typing_extra.py
Expand Up @@ -63,9 +63,10 @@ def origin_is_union(tp: type[Any] | None) -> bool:
if hasattr(typing, 'Literal'):
LITERAL_TYPES.add(typing.Literal) # type: ignore

DEPRECATED_TYPES: set[Any] = {deprecated}
# Check if `deprecated` is a type to prevent errors when using typing_extensions < 4.9.0
DEPRECATED_TYPES: tuple[Any, ...] = (deprecated,) if isinstance(deprecated, type) else ()
if hasattr(warnings, 'deprecated'):
DEPRECATED_TYPES.add(warnings.deprecated) # type: ignore
DEPRECATED_TYPES = (*DEPRECATED_TYPES, warnings.deprecated)

NONE_TYPES: tuple[Any, ...] = (None, NoneType, *(tp[None] for tp in LITERAL_TYPES))

Expand All @@ -86,7 +87,7 @@ def is_literal_type(type_: type[Any]) -> bool:


def is_deprecated_instance(instance: Any) -> bool:
return isinstance(instance, tuple(DEPRECATED_TYPES))
return isinstance(instance, DEPRECATED_TYPES)


def literal_values(type_: type[Any]) -> tuple[Any, ...]:
Expand Down
4 changes: 2 additions & 2 deletions pydantic/mypy.py
Expand Up @@ -77,7 +77,7 @@
from mypy.version import __version__ as mypy_version

from pydantic._internal import _fields
from pydantic.version import parse_mypy_version
from pydantic.version import parse_package_version

try:
from mypy.types import TypeVarDef # type: ignore[attr-defined]
Expand All @@ -104,7 +104,7 @@
}


MYPY_VERSION_TUPLE = parse_mypy_version(mypy_version)
MYPY_VERSION_TUPLE = parse_package_version(mypy_version)
BUILTINS_NAME = 'builtins' if MYPY_VERSION_TUPLE >= (0, 930) else '__builtins__'

# Increment version if plugin changes and mypy caches should be invalidated
Expand Down
14 changes: 0 additions & 14 deletions pydantic/types.py
Expand Up @@ -2822,17 +2822,3 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHa
That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded
any invalid items are discarded and the valid ones are returned.
"""


# Can't use `Field(deprecated=True)` because of a circular import
Deprecated = Annotated[T, deprecated('')]
"""
Mark a field as being deprecated.
```py
from pydantic import Deprecated, TypeAdapter
print(TypeAdapter(Deprecated[int]).json_schema())
#> {'type': 'integer', 'deprecated': True}
"""
11 changes: 4 additions & 7 deletions pydantic/version.py
Expand Up @@ -62,17 +62,14 @@ def version_info() -> str:
return '\n'.join('{:>30} {}'.format(k + ':', str(v).replace('\n', ' ')) for k, v in info.items())


def parse_mypy_version(version: str) -> tuple[int, ...]:
"""Parse mypy string version to tuple of ints.
def parse_package_version(version: str) -> tuple[int, ...]:
"""Parse a package string version to tuple of ints.
This function is included here rather than the mypy plugin file because the mypy plugin file cannot be imported
outside a mypy run.
It parses normal version like `0.930` and dev version
It parses normal version like `0.930` and extra info followed by a `+` sign
like `0.940+dev.04cac4b5d911c4f9529e6ce86a27b44f28846f5d.dirty`.
Args:
version: The mypy version string.
version: The package version string.
Returns:
A tuple of ints. e.g. (0, 930).
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Expand Up @@ -63,7 +63,7 @@ classifiers = [
]
requires-python = '>=3.8'
dependencies = [
'typing-extensions>=4.9.0',
'typing-extensions>=4.6.1',
'annotated-types>=0.4.0',
"pydantic-core==2.14.5",
]
Expand Down
12 changes: 6 additions & 6 deletions tests/mypy/test_mypy.py
Expand Up @@ -13,16 +13,16 @@
from mypy import api as mypy_api
from mypy.version import __version__ as mypy_version

from pydantic.version import parse_mypy_version
from pydantic.version import parse_package_version

except ImportError:
mypy_api = None
mypy_version = None

parse_mypy_version = lambda _: (0,) # noqa: E731
parse_package_version = lambda _: (0,) # noqa: E731


MYPY_VERSION_TUPLE = parse_mypy_version(mypy_version)
MYPY_VERSION_TUPLE = parse_package_version(mypy_version)
PYDANTIC_ROOT = Path(__file__).parent.parent.parent

pytestmark = pytest.mark.skipif(
Expand Down Expand Up @@ -132,7 +132,7 @@ def _convert_to_output_path(v: str) -> Path:
existing = None

# Build sorted list of (parsed_version, version) pairs, including the current mypy version being used
parsed_version_pairs = sorted([(parse_mypy_version(v), v) for v in existing_versions])
parsed_version_pairs = sorted([(parse_package_version(v), v) for v in existing_versions])
if MYPY_VERSION_TUPLE not in [x[0] for x in parsed_version_pairs]:
insort(parsed_version_pairs, (MYPY_VERSION_TUPLE, mypy_version))

Expand Down Expand Up @@ -259,8 +259,8 @@ def test_explicit_reexports_exist():
('0.940+dev.04cac4b5d911c4f9529e6ce86a27b44f28846f5d.dirty', (0, 940)),
],
)
def test_parse_mypy_version(v_str, v_tuple):
assert parse_mypy_version(v_str) == v_tuple
def test_parse_package_version(v_str, v_tuple):
assert parse_package_version(v_str) == v_tuple


def merge_python_and_mypy_output(source_code: str, mypy_output: str) -> str:
Expand Down
10 changes: 6 additions & 4 deletions tests/test_json_schema.py
@@ -1,3 +1,4 @@
import importlib.metadata
import json
import math
import re
Expand Down Expand Up @@ -75,7 +76,6 @@
UUID3,
UUID4,
UUID5,
Deprecated,
DirectoryPath,
FilePath,
Json,
Expand Down Expand Up @@ -5815,23 +5815,25 @@ class OuterModel(pydantic.BaseModel):
OuterModel(x=2, y=-1, z=-1)


@pytest.mark.skipif(
pydantic.version.parse_package_version(importlib.metadata.version('typing_extensions')) < (4, 9),
reason='deprecated type annotation requires typing_extensions>=4.9',
)
def test_deprecated_fields():
class Model(BaseModel):
a: Annotated[int, Field(deprecated=True)]
b: Annotated[int, Field(deprecated=False)]
c: Annotated[int, deprecated('')]
d: Annotated[int, deprecated('')] = 1
e: Deprecated[int]

assert Model.model_json_schema() == {
'properties': {
'a': {'deprecated': True, 'title': 'A', 'type': 'integer'},
'b': {'deprecated': False, 'title': 'B', 'type': 'integer'},
'c': {'deprecated': True, 'title': 'C', 'type': 'integer'},
'd': {'default': 1, 'deprecated': True, 'title': 'D', 'type': 'integer'},
'e': {'deprecated': True, 'title': 'E', 'type': 'integer'},
},
'required': ['a', 'b', 'c', 'e'],
'required': ['a', 'b', 'c'],
'title': 'Model',
'type': 'object',
}

0 comments on commit b233059

Please sign in to comment.