From 16dd46ee249084be6b823bdedc6f23e3d1dd45b1 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Wed, 21 Jan 2026 23:07:01 +0100 Subject: [PATCH 1/5] tests: add a proxyupath serialization test --- upath/tests/test_pydantic.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/upath/tests/test_pydantic.py b/upath/tests/test_pydantic.py index 00ac78db..5a743c1e 100644 --- a/upath/tests/test_pydantic.py +++ b/upath/tests/test_pydantic.py @@ -113,6 +113,21 @@ def test_dump_non_serializable_json(): ) +def test_proxyupath_serialization(): + from upath.extensions import ProxyUPath + + u = ProxyUPath("memory://my/path", some_option=True) + + ta = pydantic.TypeAdapter(ProxyUPath) + dumped = ta.dump_python(u, mode="python") + loaded = ta.validate_python(dumped) + + assert isinstance(loaded, ProxyUPath) + assert loaded.path == u.path + assert loaded.protocol == u.protocol + assert loaded.storage_options == u.storage_options + + def test_json_schema(): ta = pydantic.TypeAdapter(UPath) ta.json_schema() From 07721f65d564e0f7d6fe17ebace4e5ed7963a305 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Wed, 21 Jan 2026 23:23:35 +0100 Subject: [PATCH 2/5] tests: add a posixupath windowsupath filepath serialization test --- upath/tests/test_pydantic.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/upath/tests/test_pydantic.py b/upath/tests/test_pydantic.py index 5a743c1e..9f318841 100644 --- a/upath/tests/test_pydantic.py +++ b/upath/tests/test_pydantic.py @@ -7,6 +7,12 @@ from fsspec.implementations.http import get_client from upath import UPath +from upath.implementations.local import FilePath +from upath.implementations.local import PosixUPath +from upath.implementations.local import WindowsUPath + +from .utils import only_on_windows +from .utils import skip_on_windows @pytest.mark.parametrize( @@ -128,6 +134,28 @@ def test_proxyupath_serialization(): assert loaded.storage_options == u.storage_options +@pytest.mark.parametrize( + "path,cls", + [ + pytest.param("/my/path", PosixUPath, marks=skip_on_windows(None)), + pytest.param("C:\\my\\path", WindowsUPath, marks=only_on_windows(None)), + ("file:///my/path", FilePath), + ], +) +def test_localpath_serialization(path, cls): + u = UPath(path) + assert type(u) is cls + + ta = pydantic.TypeAdapter(cls) + dumped = ta.dump_python(u, mode="python") + loaded = ta.validate_python(dumped) + + assert isinstance(loaded, cls) + assert loaded.path == u.path + assert loaded.protocol == u.protocol + assert loaded.storage_options == u.storage_options + + def test_json_schema(): ta = pydantic.TypeAdapter(UPath) ta.json_schema() From 3909727b4f86d588fe06b5ffb5ebadafd4f7e32d Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Wed, 21 Jan 2026 23:24:46 +0100 Subject: [PATCH 3/5] upath.extensions: fix pydantic serialization --- upath/extensions.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/upath/extensions.py b/upath/extensions.py index a60e7ca8..43798177 100644 --- a/upath/extensions.py +++ b/upath/extensions.py @@ -38,6 +38,9 @@ else: from typing_extensions import Self + from pydantic import GetCoreSchemaHandler + from pydantic_core.core_schema import CoreSchema + __all__ = [ "ProxyUPath", ] @@ -576,5 +579,11 @@ def full_match( ) -> bool: return self.__wrapped__.full_match(pattern, case_sensitive=case_sensitive) + @classmethod + def __get_pydantic_core_schema__( + cls, source_type: Any, handler: GetCoreSchemaHandler + ) -> CoreSchema: + return UPath.__get_pydantic_core_schema__.__func__(cls, source_type, handler) + UPath.register(ProxyUPath) From b0bf0bb86ad0e582239f00b79e2271272823c04e Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Wed, 21 Jan 2026 23:25:23 +0100 Subject: [PATCH 4/5] upath.implementations.local: fix pydantic serialization --- upath/implementations/local.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/upath/implementations/local.py b/upath/implementations/local.py index 62f9d472..be98f7a7 100644 --- a/upath/implementations/local.py +++ b/upath/implementations/local.py @@ -48,6 +48,9 @@ from typing_extensions import Self from typing_extensions import Unpack + from pydantic import GetCoreSchemaHandler + from pydantic_core.core_schema import CoreSchema + from upath.types.storage_options import FileStorageOptions _WT = TypeVar("_WT", bound="WritablePath") @@ -725,6 +728,12 @@ def chmod( ) return super().chmod(mode) + @classmethod + def __get_pydantic_core_schema__( + cls, source_type: Any, handler: GetCoreSchemaHandler + ) -> CoreSchema: + return UPath.__get_pydantic_core_schema__.__func__(cls, source_type, handler) + UPath.register(LocalPath) From b42cb10e27d32704c21b2e66ca452e80d3937621 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Wed, 21 Jan 2026 23:39:13 +0100 Subject: [PATCH 5/5] fix typing issue --- upath/extensions.py | 3 ++- upath/implementations/local.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/upath/extensions.py b/upath/extensions.py index 43798177..f4b7f442 100644 --- a/upath/extensions.py +++ b/upath/extensions.py @@ -583,7 +583,8 @@ def full_match( def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> CoreSchema: - return UPath.__get_pydantic_core_schema__.__func__(cls, source_type, handler) + cs = UPath.__get_pydantic_core_schema__.__func__ # type: ignore[attr-defined] + return cs(cls, source_type, handler) UPath.register(ProxyUPath) diff --git a/upath/implementations/local.py b/upath/implementations/local.py index be98f7a7..884199d9 100644 --- a/upath/implementations/local.py +++ b/upath/implementations/local.py @@ -732,7 +732,8 @@ def chmod( def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> CoreSchema: - return UPath.__get_pydantic_core_schema__.__func__(cls, source_type, handler) + cs = UPath.__get_pydantic_core_schema__.__func__ # type: ignore[attr-defined] + return cs(cls, source_type, handler) UPath.register(LocalPath)