Skip to content

Commit 320425f

Browse files
authored
Fix UPath.rename type signature (#258)
* typesafety: add checks for rename signature * upath: fix type signature of UPath.rename * tests: fix issue with ssl detection on test setup
1 parent e53d8a4 commit 320425f

File tree

4 files changed

+30
-13
lines changed

4 files changed

+30
-13
lines changed

typesafety/test_upath_interface.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,3 +565,13 @@
565565
from upath import UPath
566566
567567
reveal_type(UPath("abc").walk()) # N: Revealed type is "typing.Iterator[tuple[upath.core.UPath, builtins.list[builtins.str], builtins.list[builtins.str]]]"
568+
569+
- case: upath_rename_extra_kwargs
570+
disable_cache: false
571+
main: |
572+
from upath import UPath
573+
574+
UPath("abc").rename("efg")
575+
UPath("recursive bool").rename("efg", recursive=True)
576+
UPath("maxdepth int").rename("efg", maxdepth=1)
577+
UPath("untyped extras").rename("efg", overwrite=True, something="else")

upath/core.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,14 @@
1515
from typing import Mapping
1616
from typing import Sequence
1717
from typing import TextIO
18-
from typing import TypedDict
1918
from typing import TypeVar
2019
from typing import overload
2120
from urllib.parse import urlsplit
2221

2322
if sys.version_info >= (3, 11):
2423
from typing import Self
25-
from typing import Unpack
2624
else:
2725
from typing_extensions import Self
28-
from typing_extensions import Unpack
2926

3027
from fsspec.registry import get_filesystem_class
3128
from fsspec.spec import AbstractFileSystem
@@ -94,9 +91,7 @@ def _make_instance(cls, args, kwargs):
9491
return cls(*args, **kwargs)
9592

9693

97-
class _UPathRenameParams(TypedDict, total=False):
98-
recursive: bool
99-
maxdepth: int | None
94+
_unset: Any = object()
10095

10196

10297
# accessors are deprecated
@@ -1016,7 +1011,10 @@ def rmdir(self, recursive: bool = True) -> None: # fixme: non-standard
10161011
def rename(
10171012
self,
10181013
target: str | os.PathLike[str] | UPath,
1019-
**kwargs: Unpack[_UPathRenameParams], # note: non-standard compared to pathlib
1014+
*, # note: non-standard compared to pathlib
1015+
recursive: bool = _unset,
1016+
maxdepth: int | None = _unset,
1017+
**kwargs: Any,
10201018
) -> Self:
10211019
if isinstance(target, str) and self.storage_options:
10221020
target = UPath(target, **self.storage_options)
@@ -1040,6 +1038,10 @@ def rename(
10401038
parent = parent.resolve()
10411039
target_ = parent.joinpath(os.path.normpath(target))
10421040
assert isinstance(target_, type(self)), "identical protocols enforced above"
1041+
if recursive is not _unset:
1042+
kwargs["recursive"] = recursive
1043+
if maxdepth is not _unset:
1044+
kwargs["maxdepth"] = maxdepth
10431045
self.fs.mv(
10441046
self.path,
10451047
target_.path,

upath/implementations/smb.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
import os
44
import sys
55
import warnings
6+
from typing import Any
67

78
if sys.version_info >= (3, 11):
89
from typing import Self
9-
from typing import Unpack
1010
else:
1111
from typing_extensions import Self
12-
from typing_extensions import Unpack
1312

1413
import smbprotocol.exceptions
1514

1615
from upath import UPath
17-
from upath.core import _UPathRenameParams
16+
17+
_unset: Any = object()
1818

1919

2020
class SMBPath(UPath):
@@ -44,7 +44,10 @@ def iterdir(self):
4444
def rename(
4545
self,
4646
target: str | os.PathLike[str] | UPath,
47-
**kwargs: Unpack[_UPathRenameParams], # note: non-standard compared to pathlib
47+
*,
48+
recursive: bool = _unset,
49+
maxdepth: int | None = _unset,
50+
**kwargs: Any,
4851
) -> Self:
4952
if kwargs.pop("recursive", None) is not None:
5053
warnings.warn(

upath/tests/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ def xfail_if_version(module, *, reason, **conditions):
3939
def xfail_if_no_ssl_connection(func):
4040
try:
4141
import requests
42-
42+
except ImportError:
43+
return pytest.mark.skip(reason="requests not installed")(func)
44+
try:
4345
requests.get("https://example.com")
44-
except (ImportError, requests.exceptions.SSLError):
46+
except (requests.exceptions.ConnectionError, requests.exceptions.SSLError):
4547
return pytest.mark.xfail(reason="No SSL connection")(func)
4648
else:
4749
return func

0 commit comments

Comments
 (0)