forked from pool/python-pydantic
- Add patch support-pydantic-core-2.39.0.patch:
* Support pydantic-core 2.39.0. OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-pydantic?expand=0&rev=75
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
-------------------------------------------------------------------
|
||||
Fri Aug 15 04:23:15 UTC 2025 - Steve Kowalik <steven.kowalik@suse.com>
|
||||
|
||||
- Add patch support-pydantic-core-2.39.0.patch:
|
||||
* Support pydantic-core 2.39.0.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Jun 23 05:56:23 UTC 2025 - Daniel Garcia <daniel.garcia@suse.com>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# spec file for package python-pydantic
|
||||
#
|
||||
# Copyright (c) 2025 SUSE LLC
|
||||
# Copyright (c) 2025 SUSE LLC and contributors
|
||||
# Copyright (c) 2019, Martin Hauke <mardnh@gmx.de>
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
@@ -37,11 +37,13 @@ Source: https://github.com/pydantic/pydantic/archive/v%{version}.tar.gz#
|
||||
Patch0: bump-pydantic-core-2.35.1.patch
|
||||
# PATCH-FIX-UPSTREAM field-name-validator-core-schemas.patch gh#pydantic/pydantic#11761
|
||||
Patch1: field-name-validator-core-schemas.patch
|
||||
# PATCH-FIX-UPSTREAM Based on gh#pydantic/pydantic#11883
|
||||
Patch2: support-pydantic-core-2.39.0.patch
|
||||
BuildRequires: %{python_module hatch-fancy-pypi-readme}
|
||||
BuildRequires: %{python_module hatchling}
|
||||
BuildRequires: %{python_module packaging}
|
||||
BuildRequires: %{python_module pip}
|
||||
BuildRequires: %{python_module pydantic-core = 2.35.1}
|
||||
BuildRequires: %{python_module pydantic-core = 2.39.0}
|
||||
BuildRequires: %{python_module wheel}
|
||||
BuildRequires: fdupes
|
||||
BuildRequires: python-rpm-macros
|
||||
@@ -62,10 +64,7 @@ BuildRequires: %{python_module rich}
|
||||
BuildRequires: %{python_module typing-inspection}
|
||||
%endif
|
||||
Requires: python-annotated-types >= 0.4.0
|
||||
%if 0%{?python_version_nodots} < 310
|
||||
Requires: python-eval-type-backport
|
||||
%endif
|
||||
Requires: python-pydantic-core = 2.35.1
|
||||
Requires: python-pydantic-core = 2.39.0
|
||||
Requires: python-typing-extensions >= 4.12.2
|
||||
Requires: python-typing-inspection
|
||||
BuildArch: noarch
|
||||
|
293
support-pydantic-core-2.39.0.patch
Normal file
293
support-pydantic-core-2.39.0.patch
Normal file
@@ -0,0 +1,293 @@
|
||||
From d6c65493a8436b22733d0f04d0bb3df1bc952ac9 Mon Sep 17 00:00:00 2001
|
||||
From: Viicos <65306057+Viicos@users.noreply.github.com>
|
||||
Date: Fri, 16 May 2025 15:46:24 +0200
|
||||
Subject: [PATCH 1/8] Add `UNSET` sentinel
|
||||
|
||||
---
|
||||
pydantic/_internal/_generate_schema.py | 3 +
|
||||
pydantic/fields.py | 4 +-
|
||||
pydantic/json_schema.py | 7 +-
|
||||
pyproject.toml | 2 +-
|
||||
5 files changed, 15 insertions(+), 122 deletions(-)
|
||||
|
||||
Index: pydantic-2.11.7/pydantic/_internal/_generate_schema.py
|
||||
===================================================================
|
||||
--- pydantic-2.11.7.orig/pydantic/_internal/_generate_schema.py
|
||||
+++ pydantic-2.11.7/pydantic/_internal/_generate_schema.py
|
||||
@@ -42,6 +42,7 @@ from zoneinfo import ZoneInfo
|
||||
|
||||
import typing_extensions
|
||||
from pydantic_core import (
|
||||
+ MISSING,
|
||||
CoreSchema,
|
||||
MultiHostUrl,
|
||||
PydanticCustomError,
|
||||
@@ -1050,6 +1051,8 @@ class GenerateSchema:
|
||||
return core_schema.multi_host_url_schema()
|
||||
elif obj is None or obj is _typing_extra.NoneType:
|
||||
return core_schema.none_schema()
|
||||
+ if obj is MISSING:
|
||||
+ return core_schema.missing_sentinel_schema()
|
||||
elif obj in IP_TYPES:
|
||||
return self._ip_schema(obj)
|
||||
elif obj in TUPLE_TYPES:
|
||||
Index: pydantic-2.11.7/pydantic/fields.py
|
||||
===================================================================
|
||||
--- pydantic-2.11.7.orig/pydantic/fields.py
|
||||
+++ pydantic-2.11.7/pydantic/fields.py
|
||||
@@ -15,7 +15,7 @@ from warnings import warn
|
||||
|
||||
import annotated_types
|
||||
import typing_extensions
|
||||
-from pydantic_core import PydanticUndefined
|
||||
+from pydantic_core import MISSING, PydanticUndefined
|
||||
from typing_extensions import Self, TypeAlias, Unpack, deprecated
|
||||
from typing_inspection import typing_objects
|
||||
from typing_inspection.introspection import UNKNOWN, AnnotationSource, ForbiddenQualifier, Qualifier, inspect_annotation
|
||||
@@ -392,7 +392,7 @@ class FieldInfo(_repr.Representation):
|
||||
Returns:
|
||||
A field object with the passed values.
|
||||
"""
|
||||
- if annotation is default:
|
||||
+ if annotation is not MISSING and annotation is default:
|
||||
raise PydanticUserError(
|
||||
'Error when building FieldInfo from annotated attribute. '
|
||||
"Make sure you don't have any field name clashing with a type annotation.",
|
||||
Index: pydantic-2.11.7/pydantic/json_schema.py
|
||||
===================================================================
|
||||
--- pydantic-2.11.7.orig/pydantic/json_schema.py
|
||||
+++ pydantic-2.11.7/pydantic/json_schema.py
|
||||
@@ -36,7 +36,7 @@ from typing import (
|
||||
)
|
||||
|
||||
import pydantic_core
|
||||
-from pydantic_core import CoreSchema, PydanticOmit, core_schema, to_jsonable_python
|
||||
+from pydantic_core import MISSING, CoreSchema, PydanticOmit, core_schema, to_jsonable_python
|
||||
from pydantic_core.core_schema import ComputedField
|
||||
from typing_extensions import TypeAlias, assert_never, deprecated, final
|
||||
from typing_inspection.introspection import get_literal_values
|
||||
@@ -805,6 +805,17 @@ class GenerateJsonSchema:
|
||||
result['type'] = 'null'
|
||||
return result
|
||||
|
||||
+ def missing_sentinel_schema(self, schema: core_schema.MissingSentinelSchema) -> JsonSchemaValue:
|
||||
+ """Generates a JSON schema that matches the `MISSING` sentinel value.
|
||||
+
|
||||
+ Args:
|
||||
+ schema: The core schema.
|
||||
+
|
||||
+ Returns:
|
||||
+ The generated JSON schema.
|
||||
+ """
|
||||
+ raise PydanticOmit
|
||||
+
|
||||
def enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue:
|
||||
"""Generates a JSON schema that matches an Enum value.
|
||||
|
||||
@@ -1109,7 +1120,7 @@ class GenerateJsonSchema:
|
||||
json_schema = self.generate_inner(schema['schema'])
|
||||
|
||||
default = self.get_default_value(schema)
|
||||
- if default is NoDefault:
|
||||
+ if default is NoDefault or default is MISSING:
|
||||
return json_schema
|
||||
|
||||
# we reflect the application of custom plain, no-info serializers to defaults for
|
||||
Index: pydantic-2.11.7/pydantic/version.py
|
||||
===================================================================
|
||||
--- pydantic-2.11.7.orig/pydantic/version.py
|
||||
+++ pydantic-2.11.7/pydantic/version.py
|
||||
@@ -66,7 +66,7 @@ def version_info() -> str:
|
||||
def check_pydantic_core_version() -> bool:
|
||||
"""Check that the installed `pydantic-core` dependency is compatible."""
|
||||
# Keep this in sync with the version constraint in the `pyproject.toml` dependencies:
|
||||
- return __pydantic_core_version__ == '2.35.1'
|
||||
+ return __pydantic_core_version__ == '2.39.0'
|
||||
|
||||
|
||||
def parse_mypy_version(version: str) -> tuple[int, int, int]:
|
||||
Index: pydantic-2.11.7/docs/concepts/experimental.md
|
||||
===================================================================
|
||||
--- pydantic-2.11.7.orig/docs/concepts/experimental.md
|
||||
+++ pydantic-2.11.7/docs/concepts/experimental.md
|
||||
@@ -502,3 +502,49 @@ args, kwargs = val.validate_json('{"args
|
||||
print(args, kwargs)
|
||||
#> ('arg1',) {'extra': 1}
|
||||
```
|
||||
+
|
||||
+## `MISSING` sentinel
|
||||
+
|
||||
+The `MISSING` sentinel is a singleton indicating a field value was not provided during validation.
|
||||
+
|
||||
+This singleton can be used as a default value, as an alternative to `None` when it has an explicit
|
||||
+meaning. During serialization, any field with `MISSING` as a value is excluded from the output.
|
||||
+
|
||||
+```python
|
||||
+from typing import Union
|
||||
+
|
||||
+from pydantic import BaseModel
|
||||
+from pydantic.experimental.missing_sentinel import MISSING
|
||||
+
|
||||
+
|
||||
+class Configuration(BaseModel):
|
||||
+ timeout: Union[int, None, MISSING] = MISSING
|
||||
+
|
||||
+
|
||||
+# configuration defaults, stored somewhere else:
|
||||
+defaults = {'timeout': 200}
|
||||
+
|
||||
+conf = Configuration()
|
||||
+
|
||||
+# `timeout` is excluded from the serialization output:
|
||||
+conf.model_dump()
|
||||
+# {}
|
||||
+
|
||||
+# The `MISSING` value doesn't appear in the JSON Schema:
|
||||
+Configuration.model_json_schema()['properties']['timeout']
|
||||
+#> {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'title': 'Timeout'}}
|
||||
+
|
||||
+
|
||||
+# `is` can be used to discrimate between the sentinel and other values:
|
||||
+timeout = conf.timeout if conf.timeout is not MISSING else defaults['timeout']
|
||||
+```
|
||||
+
|
||||
+This feature is marked as experimental because it relies on the draft [PEP 661](https://peps.python.org/pep-0661/), introducing sentinels in the standard library.
|
||||
+
|
||||
+As such, the following limitations currently apply:
|
||||
+
|
||||
+* Static type checking of sentinels is only supported with Pyright
|
||||
+ [1.1.402](https://github.com/microsoft/pyright/releases/tag/1.1.402)
|
||||
+ or greater, and the `enableExperimentalFeatures` type evaluation setting
|
||||
+ should be enabled.
|
||||
+* Pickling of models containing `MISSING` as a value is not supported.
|
||||
Index: pydantic-2.11.7/docs/errors/validation_errors.md
|
||||
===================================================================
|
||||
--- pydantic-2.11.7.orig/docs/errors/validation_errors.md
|
||||
+++ pydantic-2.11.7/docs/errors/validation_errors.md
|
||||
@@ -1384,6 +1384,27 @@ except ValidationError as exc:
|
||||
#> 'missing_positional_only_argument'
|
||||
```
|
||||
|
||||
+## `missing_sentinel_error`
|
||||
+
|
||||
+This error is raised when the experimental `MISSING` sentinel is the only value allowed, and wasn't
|
||||
+provided during validation:
|
||||
+
|
||||
+```python
|
||||
+from pydantic import BaseModel, ValidationError
|
||||
+from pydantic.experimental.missing_sentinel import MISSING
|
||||
+
|
||||
+
|
||||
+class Model(BaseModel):
|
||||
+ f: MISSING
|
||||
+
|
||||
+
|
||||
+try:
|
||||
+ Model(f=1)
|
||||
+except ValidationError as exc:
|
||||
+ print(repr(exc.errors()[0]['type']))
|
||||
+ #> 'missing_sentinel_error'
|
||||
+```
|
||||
+
|
||||
## `model_attributes_type`
|
||||
|
||||
This error is raised when the input value is not a valid dictionary, model instance, or instance that fields can be extracted from:
|
||||
Index: pydantic-2.11.7/pydantic/experimental/missing_sentinel.py
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ pydantic-2.11.7/pydantic/experimental/missing_sentinel.py
|
||||
@@ -0,0 +1,5 @@
|
||||
+"""Experimental module exposing a function a `MISSING` sentinel."""
|
||||
+
|
||||
+from pydantic_core import MISSING
|
||||
+
|
||||
+__all__ = ('MISSING',)
|
||||
Index: pydantic-2.11.7/pyproject.toml
|
||||
===================================================================
|
||||
--- pydantic-2.11.7.orig/pyproject.toml
|
||||
+++ pydantic-2.11.7/pyproject.toml
|
||||
@@ -46,7 +46,7 @@ dependencies = [
|
||||
'typing-extensions>=4.13.0',
|
||||
'annotated-types>=0.6.0',
|
||||
# Keep this in sync with the version in the `check_pydantic_core_version()` function:
|
||||
- 'pydantic-core==2.35.1',
|
||||
+ 'pydantic-core==2.39.0',
|
||||
'typing-inspection>=0.4.0',
|
||||
]
|
||||
dynamic = ['version', 'readme']
|
||||
Index: pydantic-2.11.7/tests/test_missing_sentinel.py
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ pydantic-2.11.7/tests/test_missing_sentinel.py
|
||||
@@ -0,0 +1,71 @@
|
||||
+import pickle
|
||||
+from typing import Union
|
||||
+
|
||||
+import pytest
|
||||
+from pydantic_core import MISSING, PydanticSerializationUnexpectedValue
|
||||
+
|
||||
+from pydantic import BaseModel, TypeAdapter, ValidationError
|
||||
+
|
||||
+
|
||||
+def test_missing_sentinel_model() -> None:
|
||||
+ class Model(BaseModel):
|
||||
+ f: Union[int, MISSING] = MISSING
|
||||
+ g: MISSING = MISSING
|
||||
+
|
||||
+ m1 = Model()
|
||||
+
|
||||
+ assert m1.model_dump() == {}
|
||||
+ assert m1.model_dump_json() == '{}'
|
||||
+
|
||||
+ m2 = Model.model_validate({'f': MISSING, 'g': MISSING})
|
||||
+
|
||||
+ assert m2.f is MISSING
|
||||
+ assert m2.g is MISSING
|
||||
+
|
||||
+ m3 = Model(f=1)
|
||||
+
|
||||
+ assert m3.model_dump() == {'f': 1}
|
||||
+ assert m3.model_dump_json() == '{"f":1}'
|
||||
+
|
||||
+
|
||||
+def test_missing_sentinel_type_adapter() -> None:
|
||||
+ """Note that this usage isn't explicitly supported (and useless in practice)."""
|
||||
+
|
||||
+ # TODO Remove annotation with PEP 747:
|
||||
+ ta: TypeAdapter[object] = TypeAdapter(MISSING)
|
||||
+
|
||||
+ assert ta.validate_python(MISSING) is MISSING
|
||||
+
|
||||
+ with pytest.raises(ValidationError) as exc_info:
|
||||
+ ta.validate_python(1)
|
||||
+
|
||||
+ assert exc_info.value.errors()[0]['type'] == 'missing_sentinel_error'
|
||||
+
|
||||
+ assert ta.dump_python(MISSING) is MISSING
|
||||
+
|
||||
+ with pytest.raises(PydanticSerializationUnexpectedValue):
|
||||
+ ta.dump_python(1)
|
||||
+
|
||||
+
|
||||
+# Defined in module to be picklable:
|
||||
+class ModelPickle(BaseModel):
|
||||
+ f: Union[int, MISSING] = MISSING
|
||||
+
|
||||
+
|
||||
+@pytest.mark.xfail(reason="PEP 661 sentinels aren't picklable yet in the experimental typing-extensions implementation")
|
||||
+def test_missing_sentinel_pickle() -> None:
|
||||
+ m = ModelPickle()
|
||||
+ m_reconstructed = pickle.loads(pickle.dumps(m))
|
||||
+
|
||||
+ assert m_reconstructed.f is MISSING
|
||||
+
|
||||
+
|
||||
+def test_missing_sentinel_json_schema() -> None:
|
||||
+ class Model(BaseModel):
|
||||
+ f: Union[int, MISSING] = MISSING
|
||||
+ g: MISSING = MISSING
|
||||
+ h: MISSING
|
||||
+
|
||||
+ assert Model.model_json_schema()['properties'] == {
|
||||
+ 'f': {'title': 'F', 'type': 'integer'},
|
||||
+ }
|
Reference in New Issue
Block a user