Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions typesafety/test_upath_signatures.yml
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,24 @@
reveal_type(p.copy_into("target_dir")) # N: Revealed type is "upath.core.UPath"
reveal_type(p.copy_into(UPath("target_dir"))) # N: Revealed type is "upath.core.UPath"

- case: upath_method_move
disable_cache: false
main: |
from upath import UPath

p = UPath("")
reveal_type(p.move("target")) # N: Revealed type is "upath.core.UPath"
reveal_type(p.move(UPath("target"))) # N: Revealed type is "upath.core.UPath"

- case: upath_method_move_into
disable_cache: false
main: |
from upath import UPath

p = UPath("")
reveal_type(p.move_into("target_dir")) # N: Revealed type is "upath.core.UPath"
reveal_type(p.move_into(UPath("target_dir"))) # N: Revealed type is "upath.core.UPath"

- case: upath_method_symlink_to
disable_cache: false
main: |
Expand Down Expand Up @@ -1017,6 +1035,10 @@
reveal_type(p.copy({{ cls }}("target"))) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.copy_into("target_dir")) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.copy_into({{ cls }}("target_dir"))) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.move("target")) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.move({{ cls }}("target"))) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.move_into("target_dir")) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.move_into({{ cls }}("target_dir"))) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.rename("new_name")) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.rename({{ cls }}("new_name"))) # N: Revealed type is "{{ module }}.{{ cls }}"
reveal_type(p.replace("target")) # N: Revealed type is "{{ module }}.{{ cls }}"
Expand Down
29 changes: 29 additions & 0 deletions upath/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,35 @@ def copy_into(
else:
return super().copy_into(target_dir, **kwargs)

@overload
def move(self, target: _WT, **kwargs: Any) -> _WT: ...

@overload
def move(self, target: SupportsPathLike | str, **kwargs: Any) -> Self: ...

def move(self, target: _WT | SupportsPathLike | str, **kwargs: Any) -> _WT | UPath:
target = self.copy(target, **kwargs)
self.fs.rm(self.path, recursive=self.is_dir())
return target

@overload
def move_into(self, target_dir: _WT, **kwargs: Any) -> _WT: ...

@overload
def move_into(self, target_dir: SupportsPathLike | str, **kwargs: Any) -> Self: ...

def move_into(
self, target_dir: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | UPath:
name = self.name
if not name:
raise ValueError(f"{self!r} has an empty name")
elif hasattr(target_dir, "with_segments"):
target = target_dir.with_segments(target_dir, name) # type: ignore
else:
target = self.with_segments(target_dir, name)
return self.move(target)

# --- WritablePath attributes -------------------------------------

def symlink_to(
Expand Down
6 changes: 6 additions & 0 deletions upath/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,12 @@ def copy(self, target: WritablePathLike, **kwargs: Any) -> Self: # type: ignore
def copy_into(self, target_dir: WritablePathLike, **kwargs: Any) -> Self: # type: ignore[override] # noqa: E501
return self._from_upath(self.__wrapped__.copy_into(target_dir, **kwargs))

def move(self, target: WritablePathLike, **kwargs: Any) -> Self: # type: ignore[override] # noqa: E501
return self._from_upath(self.__wrapped__.move(target, **kwargs))

def move_into(self, target_dir: WritablePathLike, **kwargs: Any) -> Self: # type: ignore[override] # noqa: E501
return self._from_upath(self.__wrapped__.move_into(target_dir, **kwargs))

def write_bytes(self, data: bytes) -> int:
return self.__wrapped__.write_bytes(data)

Expand Down
2 changes: 2 additions & 0 deletions upath/implementations/cached.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from upath.core import UPath


Expand Down
10 changes: 6 additions & 4 deletions upath/implementations/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import sys
from collections.abc import Sequence
from typing import TYPE_CHECKING

from upath.core import UPath
from upath.types import JoinablePathLike

if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self
if TYPE_CHECKING:
if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self


class DataPath(UPath):
Expand Down
12 changes: 8 additions & 4 deletions upath/implementations/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
GitHub file system implementation
"""

from __future__ import annotations

import sys
from collections.abc import Iterator
from collections.abc import Sequence
from typing import TYPE_CHECKING

import upath.core

if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self
if TYPE_CHECKING:
if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self


class GitHubPath(upath.core.UPath):
Expand Down
10 changes: 6 additions & 4 deletions upath/implementations/hdfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import sys
from collections.abc import Iterator
from typing import TYPE_CHECKING

from upath.core import UPath

if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self
if TYPE_CHECKING:
if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self

__all__ = ["HDFSPath"]

Expand Down
35 changes: 34 additions & 1 deletion upath/implementations/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def open(
**fsspec_kwargs,
)

if sys.version_info < (3, 14):
if sys.version_info < (3, 14): # noqa: C901

@overload
def copy(self, target: _WT, **kwargs: Any) -> _WT: ...
Expand Down Expand Up @@ -350,6 +350,39 @@ def copy_into(
else:
return _copy_into(target_dir, **kwargs)

@overload
def move(self, target: _WT, **kwargs: Any) -> _WT: ...

@overload
def move(self, target: SupportsPathLike | str, **kwargs: Any) -> Self: ...

def move(
self, target: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | Self:
target = self.copy(target, **kwargs)
self.fs.rm(self.path, recursive=self.is_dir())
return target

@overload
def move_into(self, target_dir: _WT, **kwargs: Any) -> _WT: ...

@overload
def move_into(
self, target_dir: SupportsPathLike | str, **kwargs: Any
) -> Self: ...

def move_into(
self, target_dir: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | Self:
name = self.name
if not name:
raise ValueError(f"{self!r} has an empty name")
elif hasattr(target_dir, "with_segments"):
target = target_dir.with_segments(str(target_dir), name) # type: ignore
else:
target = self.with_segments(str(target_dir), name)
return self.move(target)

@property
def info(self) -> PathInfo:
return _LocalPathInfo(self)
Expand Down
10 changes: 6 additions & 4 deletions upath/implementations/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import sys
from collections.abc import Iterator
from typing import TYPE_CHECKING

from upath.core import UPath

if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self
if TYPE_CHECKING:
if sys.version_info > (3, 11):
from typing import Self
else:
from typing_extensions import Self

__all__ = ["MemoryPath"]

Expand Down
43 changes: 43 additions & 0 deletions upath/tests/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,3 +606,46 @@ def test_copy_into_memory(self, clear_fsspec_memory_cache):
target = target_dir / "file1.txt"
assert target.exists()
assert target.read_text() == content

def test_move_local(self, tmp_path: Path):
target = UPath(tmp_path) / "target-file1.txt"

source = self.path / "file1.txt"
content = source.read_text()
source.move(target)
assert target.exists()
assert target.read_text() == content
assert not source.exists()

def test_move_into_local(self, tmp_path: Path):
target_dir = UPath(tmp_path) / "target-dir"
target_dir.mkdir()

source = self.path / "file1.txt"
content = source.read_text()
source.move_into(target_dir)
target = target_dir / "file1.txt"
assert target.exists()
assert target.read_text() == content
assert not source.exists()

def test_move_memory(self, clear_fsspec_memory_cache):
target = UPath("memory:///target-file1.txt")
source = self.path / "file1.txt"
content = source.read_text()
source.move(target)
assert target.exists()
assert target.read_text() == content
assert not source.exists()

def test_move_into_memory(self, clear_fsspec_memory_cache):
target_dir = UPath("memory:///target-dir")
target_dir.mkdir()

source = self.path / "file1.txt"
content = source.read_text()
source.move_into(target_dir)
target = target_dir / "file1.txt"
assert target.exists()
assert target.read_text() == content
assert not source.exists()
16 changes: 16 additions & 0 deletions upath/tests/implementations/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,19 @@ def test_copy_into_memory(self, clear_fsspec_memory_cache):
target = target_dir / source.name
assert target.exists()
assert target.read_text() == content

@pytest.mark.skip(reason="DataPath does not support unlink")
def test_move_local(self, tmp_path):
pass

@pytest.mark.skip(reason="DataPath does not support unlink")
def test_move_into_local(self, tmp_path):
pass

@pytest.mark.skip(reason="DataPath does not support unlink")
def test_move_memory(self, clear_fsspec_memory_cache):
pass

@pytest.mark.skip(reason="DataPath does not support unlink")
def test_move_into_memory(self, clear_fsspec_memory_cache):
pass
16 changes: 16 additions & 0 deletions upath/tests/implementations/test_github.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,19 @@ def test_write_text(self):
@pytest.mark.skip(reason="GitHub filesystem is read-only")
def test_fsspec_compat(self):
pass

@pytest.mark.skip(reason="Only testing read on GithubPath")
def test_move_local(self, tmp_path):
pass

@pytest.mark.skip(reason="Only testing read on GithubPath")
def test_move_into_local(self, tmp_path):
pass

@pytest.mark.skip(reason="Only testing read on GithubPath")
def test_move_memory(self, clear_fsspec_memory_cache):
pass

@pytest.mark.skip(reason="Only testing read on GithubPath")
def test_move_into_memory(self, clear_fsspec_memory_cache):
pass
16 changes: 16 additions & 0 deletions upath/tests/implementations/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@ def test_info(self):
assert p1.info.is_dir() is True
assert p1.info.is_symlink() is False

@pytest.mark.skip(reason="HttpPath does not support unlink")
def test_move_local(self, tmp_path):
pass

@pytest.mark.skip(reason="HttpPath does not support unlink")
def test_move_into_local(self, tmp_path):
pass

@pytest.mark.skip(reason="HttpPath does not support unlink")
def test_move_memory(self, clear_fsspec_memory_cache):
pass

@pytest.mark.skip(reason="HttpPath does not support unlink")
def test_move_into_memory(self, clear_fsspec_memory_cache):
pass


@pytest.mark.parametrize(
"args,parts",
Expand Down