diff --git a/upath/extensions.py b/upath/extensions.py index 84d56798..d75dd43b 100644 --- a/upath/extensions.py +++ b/upath/extensions.py @@ -16,6 +16,7 @@ from urllib.parse import SplitResult from fsspec import AbstractFileSystem +from pathlib_abc import vfspath from upath._chain import Chain from upath._chain import ChainSegment @@ -160,6 +161,8 @@ def symlink_to( target: ReadablePathLike, target_is_directory: bool = False, ) -> None: + if not isinstance(target, str): + target = vfspath(target) self.__wrapped__.symlink_to(target, target_is_directory=target_is_directory) def mkdir( @@ -431,6 +434,8 @@ def is_relative_to(self, other, /, *_deprecated) -> bool: # type: ignore[overri return self.__wrapped__.is_relative_to(other, *_deprecated) def hardlink_to(self, target: ReadablePathLike) -> None: + if not isinstance(target, str): + target = vfspath(target) return self.__wrapped__.hardlink_to(target) def match(self, pattern: str, *, case_sensitive: bool | None = None) -> bool: diff --git a/upath/implementations/local.py b/upath/implementations/local.py index 7506b435..739c78aa 100644 --- a/upath/implementations/local.py +++ b/upath/implementations/local.py @@ -642,7 +642,7 @@ def relative_to( # type: ignore[override] def hardlink_to(self, target: ReadablePathLike) -> None: try: - os.link(target, self) # type: ignore[arg-type] + os.link(os.fspath(target), os.fspath(self)) # type: ignore[arg-type] except AttributeError: raise UnsupportedOperation("hardlink operation not supported") diff --git a/upath/tests/test_extensions.py b/upath/tests/test_extensions.py index c3976957..fdd802a5 100644 --- a/upath/tests/test_extensions.py +++ b/upath/tests/test_extensions.py @@ -1,5 +1,6 @@ import os import sys +from contextlib import nullcontext import pytest @@ -130,6 +131,30 @@ def test_cwd(self): with pytest.raises(UnsupportedOperation): type(self.path).cwd() + def test_lchmod(self): + # setup + a = self.path.joinpath("a") + b = self.path.joinpath("b") + a.touch() + b.symlink_to(a) + + # see: https://github.com/python/cpython/issues/108660#issuecomment-1854645898 + if hasattr(os, "lchmod") or os.chmod in os.supports_follow_symlinks: + cm = nullcontext() + else: + cm = pytest.raises((UnsupportedOperation, NotImplementedError)) + with cm: + b.lchmod(mode=0o777) + + def test_symlink_to(self): + self.path.joinpath("link").symlink_to(self.path) + + def test_hardlink_to(self): + try: + self.path.joinpath("link").hardlink_to(self.path) + except PermissionError: + pass # hardlink may require elevated permissions + def test_custom_subclass():