Skip to content

Commit eb08231

Browse files
authored
UPath api extensions via upath.extensions.ProxyUPath (fsspec#372)
* upath.core: minor typing fixes * upath.extensions: support API extensions via ProxyUPath * upath.extensions: minor fixes * tests: add tests for upath.extensions * tests: remove obsolete test override in hdfs test * upath.extensions: fixing typing and UPath.rename * upath.core: early return in UPath.rename
1 parent 697cf7f commit eb08231

File tree

6 files changed

+588
-26
lines changed

6 files changed

+588
-26
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ celerybeat.pid
109109
.venv
110110
env/
111111
venv/
112+
venv*/
112113
ENV/
113114
env.bak/
114115
venv.bak/

upath/core.py

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def iterdir(self) -> Iterator[Self]:
458458
_, _, name = name.removesuffix(sep).rpartition(self.parser.sep)
459459
yield base.with_segments(str(base), name)
460460

461-
def __open_rb__(self, buffering=-1) -> BinaryIO:
461+
def __open_rb__(self, buffering: int = -1) -> BinaryIO:
462462
block_size = _buffering2blocksize("wb", buffering)
463463
kw = {}
464464
if block_size is not None:
@@ -470,14 +470,19 @@ def readlink(self) -> Self:
470470

471471
# --- WritablePath attributes -------------------------------------
472472

473-
def symlink_to( # type: ignore[override]
473+
def symlink_to(
474474
self,
475-
target: str | os.PathLike[str] | UPath,
475+
target: ReadablePathLike,
476476
target_is_directory: bool = False,
477477
) -> None:
478478
raise NotImplementedError
479479

480-
def mkdir(self, mode=0o777, parents=False, exist_ok=False) -> None:
480+
def mkdir(
481+
self,
482+
mode: int = 0o777,
483+
parents: bool = False,
484+
exist_ok: bool = False,
485+
) -> None:
481486
if parents and not exist_ok and self.exists():
482487
raise FileExistsError(str(self))
483488
try:
@@ -492,7 +497,7 @@ def mkdir(self, mode=0o777, parents=False, exist_ok=False) -> None:
492497
if not self.is_dir():
493498
raise FileExistsError(str(self))
494499

495-
def __open_wb__(self, buffering=-1) -> BinaryIO:
500+
def __open_wb__(self, buffering: int = -1) -> BinaryIO:
496501
block_size = _buffering2blocksize("wb", buffering)
497502
kw = {}
498503
if block_size is not None:
@@ -504,7 +509,7 @@ def __open_wb__(self, buffering=-1) -> BinaryIO:
504509
@overload
505510
def open(
506511
self,
507-
mode: Literal["r", "w", "a"] = "r",
512+
mode: Literal["r", "w", "a"] = ...,
508513
buffering: int = ...,
509514
encoding: str = ...,
510515
errors: str = ...,
@@ -515,18 +520,32 @@ def open(
515520
@overload
516521
def open(
517522
self,
518-
mode: Literal["rb", "wb", "ab"],
523+
mode: Literal["rb", "wb", "ab"] = ...,
519524
buffering: int = ...,
520525
encoding: str = ...,
521526
errors: str = ...,
522527
newline: str = ...,
523528
**fsspec_kwargs: Any,
524529
) -> BinaryIO: ...
525530

531+
@overload
532+
def open(
533+
self,
534+
mode: str = ...,
535+
buffering: int = ...,
536+
encoding: str | None = ...,
537+
errors: str | None = ...,
538+
newline: str | None = ...,
539+
**fsspec_kwargs: Any,
540+
) -> IO[Any]: ...
541+
526542
def open(
527543
self,
528544
mode: str = "r",
529-
*args: Any,
545+
buffering: int = UNSET_DEFAULT,
546+
encoding: str | None = UNSET_DEFAULT,
547+
errors: str | None = UNSET_DEFAULT,
548+
newline: str | None = UNSET_DEFAULT,
530549
**fsspec_kwargs: Any,
531550
) -> IO[Any]:
532551
"""
@@ -549,19 +568,18 @@ def open(
549568
Additional options for the fsspec filesystem.
550569
"""
551570
# match the signature of pathlib.Path.open()
552-
for key, value in zip(["buffering", "encoding", "errors", "newline"], args):
553-
if key in fsspec_kwargs:
554-
raise TypeError(
555-
f"{type(self).__name__}.open() got multiple values for '{key}'"
556-
)
557-
fsspec_kwargs[key] = value
558-
# translate pathlib buffering to fs block_size
559-
if "buffering" in fsspec_kwargs:
571+
if buffering is not UNSET_DEFAULT:
560572
if "block_size" in fsspec_kwargs:
561573
raise TypeError("cannot specify both 'buffering' and 'block_size'")
562-
block_size = _buffering2blocksize(mode, fsspec_kwargs.pop("buffering"))
574+
block_size = _buffering2blocksize(mode, buffering)
563575
if block_size is not None:
564576
fsspec_kwargs.setdefault("block_size", block_size)
577+
if encoding is not UNSET_DEFAULT:
578+
fsspec_kwargs["encoding"] = encoding
579+
if errors is not UNSET_DEFAULT:
580+
fsspec_kwargs["errors"] = errors
581+
if newline is not UNSET_DEFAULT:
582+
fsspec_kwargs["newline"] = newline
565583
return self.fs.open(self.path, mode=mode, **fsspec_kwargs)
566584

567585
# === pathlib.Path ================================================
@@ -807,6 +825,8 @@ def rename(
807825
) -> Self:
808826
if isinstance(target, str) and self.storage_options:
809827
target = UPath(target, **self.storage_options)
828+
if target == self:
829+
return self
810830
target_protocol = get_upath_protocol(target)
811831
if target_protocol:
812832
if target_protocol != self.protocol:
@@ -826,7 +846,6 @@ def rename(
826846
if ".." in parent.parts or "." in parent.parts:
827847
parent = parent.resolve()
828848
target_ = parent.joinpath(os.path.normpath(str(target)))
829-
assert isinstance(target_, type(self)), "identical protocols enforced above"
830849
if recursive is not UNSET_DEFAULT:
831850
kwargs["recursive"] = recursive
832851
if maxdepth is not UNSET_DEFAULT:
@@ -836,9 +855,9 @@ def rename(
836855
target_.path,
837856
**kwargs,
838857
)
839-
return target_
858+
return self.with_segments(target_)
840859

841-
def replace(self, target: str | os.PathLike[str] | UPath) -> UPath:
860+
def replace(self, target: WritablePathLike) -> Self:
842861
raise NotImplementedError # todo
843862

844863
@property

0 commit comments

Comments
 (0)