pydantic: FTBFS against python 3.15rc1
Maximiliano Curia <[email protected]>
| Newsgroups | gmane.linux.debian.devel.python |
|---|---|
| Message-ID | <[email protected]> |
Package: src:pydantic Version: 2.13.4-3 User: [email protected] Usertags: python3.15 Tags: patch Hi! While rebuilding the python related packages against the Python 3.15rc1 version we found that pydantic fails to build from source [1]. We found that the necessary fixes have recently been applied in the upstream repository [2]. I applied the upstream fix in the sandbox [3] to be able to build the packages that depend on pydantic, please consider applying the patch to support the upcoming 3.15 version. Happy hacking, [1]: https://debusine.debian.net/debian/r-python-python3.15/artifact/4439432/ [2]: https://github.com/pydantic/pydantic/pull/13587 [3]: https://debusine.debian.net/debian/r-python-python3.15/ -- "Can you imagine what I would do if I could do all I can?" -- Sun Tzu Saludos /\/\ /\ >< `/
fix-compat-with-base64.patch
(text/x-diff, 6.4 KB)
commit b348cf0dce91e1cf1a3e918402e4bb8e4e6203b2 Author: Victorien <[email protected]> Date: Thu Aug 6 13:34:53 2026 +0200 Add initial support for Python 3.15 (#13587) Index: pydantic/pydantic/_internal/_model_construction.py =================================================================== --- pydantic.orig/pydantic/_internal/_model_construction.py +++ pydantic/pydantic/_internal/_model_construction.py @@ -8,6 +8,7 @@ import typing import warnings import weakref from abc import ABCMeta +from collections.abc import MutableMapping from functools import cache, partial, wraps from types import FunctionType from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, NoReturn, TypeVar, cast @@ -812,7 +813,7 @@ class _PydanticWeakRef: return _PydanticWeakRef, (self(),) -def build_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: +def build_lenient_weakvaluedict(d: MutableMapping[str, Any] | None) -> dict[str, Any] | None: """Takes an input dictionary, and produces a new value that (invertibly) replaces the values with weakrefs. We can't just use a WeakValueDictionary because many types (including int, str, etc.) can't be stored as values Index: pydantic/pydantic/_internal/_typing_extra.py =================================================================== --- pydantic.orig/pydantic/_internal/_typing_extra.py +++ pydantic/pydantic/_internal/_typing_extra.py @@ -7,6 +7,7 @@ import re import sys import types import typing +from collections.abc import MutableMapping from functools import partial from inspect import Signature, signature from typing import TYPE_CHECKING, Any, Callable, cast @@ -212,7 +213,7 @@ typing_base: Any = typing._Final # pyri ### Annotation evaluations functions: -def parent_frame_namespace(*, parent_depth: int = 2, force: bool = False) -> dict[str, Any] | None: +def parent_frame_namespace(*, parent_depth: int = 2, force: bool = False) -> MutableMapping[str, Any] | None: """Fetch the local namespace of the parent frame where this function is called. Using this function is mostly useful to resolve forward annotations pointing to members defined in a local namespace, Index: pydantic/pydantic/types.py =================================================================== --- pydantic.orig/pydantic/types.py +++ pydantic/pydantic/types.py @@ -5,6 +5,7 @@ from __future__ import annotations as _a import base64 import dataclasses as _dataclasses import re +import sys from collections.abc import Hashable, Iterator from datetime import date, datetime from decimal import Decimal @@ -2434,6 +2435,9 @@ class Base64Encoder(EncoderProtocol): return 'base64' +_urlsafe_translation = bytes.maketrans(b'+/', b'-_') + + class Base64UrlEncoder(EncoderProtocol): """URL-safe Base64 encoder.""" @@ -2448,7 +2452,15 @@ class Base64UrlEncoder(EncoderProtocol): The decoded data. """ try: - return base64.urlsafe_b64decode(data) + if sys.version_info >= (3, 15): + # In Python >= 3.15, `urlsafe_b64decode()` doesn't require padded input anymore. + # It also raises a `FutureWarning` if '+' or '/' is found in input (and translates it + # to '-' and '_'). We can't have this warning raised while validating, so we do the translation + # ourselves. + data = data.translate(_urlsafe_translation) + return base64.urlsafe_b64decode(data, padded=True) + else: + return base64.urlsafe_b64decode(data) except ValueError as e: raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) @@ -2799,11 +2811,8 @@ Base64UrlBytes = Annotated[bytes, Encode """A bytes type that is encoded and decoded using the URL-safe base64 encoder. Note: - Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` - functions. - - As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data - (using `'+'` and `'/'`). + Under the hood, `Base64UrlBytes` uses the standard library [`base64.urlsafe_b64encode()`][base64.urlsafe_b64encode] + and [`base64.urlsafe_b64decode()`][base64.urlsafe_b64decode] functions. ```python from pydantic import Base64UrlBytes, BaseModel @@ -2821,10 +2830,8 @@ Base64UrlStr = Annotated[str, EncodedStr """A str type that is encoded and decoded using the URL-safe base64 encoder. Note: - Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` - functions. - - As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`). + Under the hood, `Base64UrlStr` uses the standard library [`base64.urlsafe_b64encode()`][base64.urlsafe_b64encode] + and [`base64.urlsafe_b64decode()`][base64.urlsafe_b64decode] functions. ```python from pydantic import Base64UrlStr, BaseModel Index: pydantic/pyproject.toml =================================================================== --- pydantic.orig/pyproject.toml +++ pydantic/pyproject.toml @@ -34,6 +34,7 @@ classifiers = [ 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', + 'Programming Language :: Python :: 3.15', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Operating System :: OS Independent', @@ -117,7 +118,8 @@ testing-extra = [ 'devtools', # used in docs tests 'sqlalchemy', - 'pytest-memray; platform_python_implementation == "CPython" and platform_system != "Windows"', + 'pytest-memray; platform_python_implementation == "CPython" and platform_system != "Windows" and python_version < "3.15"', + 'memray; platform_python_implementation == "CPython" and platform_system != "Windows" and python_version < "3.15"', ] typechecking = [ 'mypy', Index: pydantic/tests/test_generics.py =================================================================== --- pydantic.orig/tests/test_generics.py +++ pydantic/tests/test_generics.py @@ -2295,6 +2295,7 @@ def test_parse_generic_json(): } [email protected](sys.version_info >= (3, 15), reason="memray doesn't yet support Python 3.15") def memray_limit_memory(limit): if '--memray' in sys.argv: return pytest.mark.limit_memory(limit)