diff --git a/upath/_info.py b/upath/_info.py new file mode 100644 index 00000000..03743285 --- /dev/null +++ b/upath/_info.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from upath.types import PathInfo + +if TYPE_CHECKING: + from upath import UPath + + +__all__ = [ + "UPathInfo", +] + + +class UPathInfo(PathInfo): + """Path info for UPath objects.""" + + def __init__(self, path: UPath) -> None: + self._path = path.path + self._fs = path.fs + + def exists(self, *, follow_symlinks=True) -> bool: + return self._fs.exists(self._path) + + def is_dir(self, *, follow_symlinks=True) -> bool: + return self._fs.isdir(self._path) + + def is_file(self, *, follow_symlinks=True) -> bool: + return self._fs.isfile(self._path) + + def is_symlink(self) -> bool: + return False diff --git a/upath/core.py b/upath/core.py index cc3fd465..1c86665c 100644 --- a/upath/core.py +++ b/upath/core.py @@ -31,6 +31,7 @@ from upath._flavour import WrappedFileSystemFlavour from upath._flavour import upath_get_kwargs_from_url from upath._flavour import upath_urijoin +from upath._info import UPathInfo from upath._protocol import compatible_protocol from upath._protocol import get_upath_protocol from upath._stat import UPathStatResult @@ -574,7 +575,7 @@ def parents(self) -> Sequence[Self]: @property def info(self) -> PathInfo: - _raise_unsupported(type(self).__name__, "info") + return UPathInfo(self) def iterdir(self) -> Iterator[Self]: sep = self.parser.sep diff --git a/upath/tests/cases.py b/upath/tests/cases.py index 29bb21b2..06cb35aa 100644 --- a/upath/tests/cases.py +++ b/upath/tests/cases.py @@ -554,3 +554,16 @@ def test_samefile(self): assert f1.samefile(f2.path) is False assert f1.samefile(f1) is True assert f1.samefile(f1.path) is True + + def test_info(self): + p0 = self.path.joinpath("file1.txt") + p1 = self.path.joinpath("folder1") + + assert p0.info.exists() is True + assert p0.info.is_file() is True + assert p0.info.is_dir() is False + assert p0.info.is_symlink() is False + assert p1.info.exists() is True + assert p1.info.is_file() is False + assert p1.info.is_dir() is True + assert p1.info.is_symlink() is False diff --git a/upath/tests/implementations/test_data.py b/upath/tests/implementations/test_data.py index 2de99686..a1fd3bd1 100644 --- a/upath/tests/implementations/test_data.py +++ b/upath/tests/implementations/test_data.py @@ -216,3 +216,11 @@ def test_samefile(self): f1 = self.path assert f1.samefile(f1) is True + + def test_info(self): + p0 = self.path + + assert p0.info.exists() is True + assert p0.info.is_file() is True + assert p0.info.is_dir() is False + assert p0.info.is_symlink() is False diff --git a/upath/tests/implementations/test_http.py b/upath/tests/implementations/test_http.py index cd5b5966..170ad197 100644 --- a/upath/tests/implementations/test_http.py +++ b/upath/tests/implementations/test_http.py @@ -126,6 +126,21 @@ def test_rename2(self): def test_stat_dir_st_mode(self): super().test_stat_dir_st_mode() + def test_info(self): + p0 = self.path.joinpath("file1.txt") + p1 = self.path.joinpath("folder1") + + assert p0.info.exists() is True + assert p0.info.is_file() is True + assert p0.info.is_dir() is False + assert p0.info.is_symlink() is False + assert p1.info.exists() is True + assert ( + p1.info.is_file() is True + ) # Weird quirk of how directories work in http fsspec + assert p1.info.is_dir() is True + assert p1.info.is_symlink() is False + @pytest.mark.parametrize( "args,parts",