Skip to content

Commit 00924c1

Browse files
authored
Support relative paths (#405)
* tests: add relative path tests * upath: initial relative path implementation * tests: adjust relative_to tests * Various fixes for windows and typesafety * upath: don't make cwd() abstract in mixin * upath: as_uri() for relative paths * upath: add tests for file access on relative paths * upath: relative path drive,root,anchor fixes * upath: more relative path tests * tests: fix typo in relative path suffixes test * tests: add .parent tests for relative paths * upath: repr for relative paths * tests: relpath tests for parent(s), protocol, storage_options, path, fs and home * tests: parser and resolve tests * tests: add tests for relative path .match * tests: add tests for joinpath * upath: return dynamically created subclasses for untested protocols * upath: fix relative-path support for with_segments * upath: fix __vfspath__ for relative paths * upath: fix parent for relative paths * upath: .parents implementation for relative paths * upath: fix FilePath.cwd() and FilePath.home() * upath: fix pickling of dynamically created classes * tests: fix .cwd and .home tests in core * upath: fix remaining relative path tests * tests: fix windows path separator comparisons * tests: fix file uri comparison * tests: relative joinpath fix windows separator comparison * upath.implementations.cloud: fix GCSPath.exists() for gcsfs<2025.5.0 * tests: add mulitple join tests for different local/fsspec combinations * upath: fix joinpath for relative upaths * upath: fix local joinpath stringification
1 parent 87ff1fb commit 00924c1

File tree

11 files changed

+1003
-53
lines changed

11 files changed

+1003
-53
lines changed

upath/_flavour.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from fsspec.registry import registry as _class_registry
1818
from fsspec.spec import AbstractFileSystem
1919

20+
import upath
2021
from upath._flavour_sources import FileSystemFlavourBase
2122
from upath._flavour_sources import flavour_registry
2223
from upath._protocol import get_upath_protocol
@@ -239,12 +240,14 @@ def local_file(self) -> bool:
239240
def stringify_path(pth: PathOrStr) -> str:
240241
if isinstance(pth, str):
241242
out = pth
243+
elif isinstance(pth, upath.UPath) and not pth.is_absolute():
244+
out = str(pth)
242245
elif getattr(pth, "__fspath__", None) is not None:
243246
assert hasattr(pth, "__fspath__")
244247
out = pth.__fspath__()
245248
elif isinstance(pth, os.PathLike):
246249
out = str(pth)
247-
elif hasattr(pth, "path"): # type: ignore[unreachable]
250+
elif isinstance(pth, upath.UPath) and pth.is_absolute():
248251
out = pth.path
249252
else:
250253
out = str(pth)
@@ -288,7 +291,7 @@ def join(self, path: PathOrStr, *paths: PathOrStr) -> str:
288291
if self.local_file:
289292
return os.path.join(
290293
self.strip_protocol(path),
291-
*paths, # type: ignore[arg-type]
294+
*map(self.stringify_path, paths),
292295
)
293296
if self.netloc_is_anchor:
294297
drv, p0 = self.splitdrive(path)

upath/_protocol.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,12 @@ def compatible_protocol(
105105
*args: str | os.PathLike[str] | PurePath | JoinablePath,
106106
) -> bool:
107107
"""check if UPath protocols are compatible"""
108+
from upath.core import UPath
109+
108110
for arg in args:
111+
if isinstance(arg, UPath) and not arg.is_absolute():
112+
# relative UPath are always compatible
113+
continue
109114
other_protocol = get_upath_protocol(arg)
110115
# consider protocols equivalent if they match up to the first "+"
111116
other_protocol = other_protocol.partition("+")[0]

0 commit comments

Comments
 (0)