Skip to content

Commit b4a5151

Browse files
committed
lets paths function the same in upath as fsspec
1 parent 312aafe commit b4a5151

File tree

8 files changed

+53
-212
lines changed

8 files changed

+53
-212
lines changed

upath/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def __new__(cls, *args, **kwargs):
1616
for key in ["scheme", "netloc"]:
1717
val = kwargs.get(key)
1818
if val:
19-
parsed_url._replace(**{key: val})
19+
parsed_url = parsed_url._replace(**{key: val})
2020
# treat as local filesystem, return PosixPath or WindowsPath
2121
impls = list(registry) + list(known_implementations.keys())
2222
if not parsed_url.scheme or parsed_url.scheme not in impls:

upath/implementations/memory.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
class _MemoryAccessor(_FSSpecAccessor):
55
def __init__(self, *args, **kwargs):
66
super().__init__(*args, **kwargs)
7+
self._fs.root_marker = ""
8+
9+
def _format_path(self, s):
10+
"""If the filesystem backend doesn't have a root_marker, strip the
11+
leading slash of a path
12+
"""
13+
return s
714

815

916
class MemoryPath(UniversalPath):

upath/tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def pytest_collection_modifyitems(config, items):
3434

3535
class DummyTestFS(LocalFileSystem):
3636
protocol = "mock"
37+
root_marker = '/'
3738

3839

3940
@pytest.fixture(scope="session")

upath/tests/implementations/test_hdfs.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
from upath import UPath
66
from upath.implementations.hdfs import HDFSPath
7-
from upath.tests.test_core import TestUpath
7+
from upath.tests.cases import BaseTests
88

99

1010
@pytest.mark.hdfs
11-
class TestUPathHDFS(TestUpath):
11+
class TestUPathHDFS(BaseTests):
1212
@pytest.fixture(autouse=True)
1313
def path(self, local_testdir, hdfs):
1414
host, user, port = hdfs
@@ -21,3 +21,6 @@ def test_is_HDFSPath(self):
2121
def test_chmod(self):
2222
# todo
2323
pass
24+
25+
def test_fsspec_compat(self):
26+
pass

upath/tests/implementations/test_memory.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
from upath import UPath
55
from upath.implementations.memory import MemoryPath
6-
from upath.tests.test_core import TestUpath
6+
from upath.tests.cases import BaseTests
77

88

9-
class TestMemoryPath(TestUpath):
9+
class TestMemoryPath(BaseTests):
10+
1011
@pytest.fixture(autouse=True)
1112
def path(self, local_testdir):
1213
path = f"memory:/{local_testdir}"

upath/tests/implementations/test_s3.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@
22
"""
33
import pytest # noqa: F401
44

5+
from s3fs import S3FileSystem
6+
57
from upath import UPath
68
from upath.errors import NotDirectoryError
79
from upath.implementations.s3 import S3Path
8-
from upath.tests.test_core import TestUpath
10+
from upath.tests.cases import BaseTests
911

1012

11-
class TestUPathS3(TestUpath):
13+
class TestUPathS3(BaseTests):
14+
1215
@pytest.fixture(autouse=True)
1316
def path(self, local_testdir, s3):
1417
anon, s3so = s3
1518
path = f"s3:/{local_testdir}"
16-
print(path)
1719
self.path = UPath(path, anon=anon, **s3so)
20+
self.anon = anon
21+
self.s3so = s3so
22+
1823

1924
def test_is_S3Path(self):
2025
assert isinstance(self.path, S3Path)
@@ -62,3 +67,23 @@ def test_glob(self, pathlib_base):
6267
assert all(
6368
map(lambda m: m.path in [str(p)[4:] for p in path_glob], mock_glob)
6469
)
70+
71+
def test_fsspec_compat(self):
72+
fs = self.path.fs
73+
scheme = self.path._url.scheme
74+
content = b"a,b,c\n1,2,3\n4,5,6"
75+
76+
p1 = f"{scheme}:///tmp/output1.csv"
77+
upath1 = UPath(p1, anon=self.anon, **self.s3so)
78+
upath1.write_bytes(content)
79+
with fs.open(p1) as f:
80+
assert f.read() == content
81+
upath1.unlink()
82+
83+
# write with fsspec, read with upath
84+
p2 = f"{scheme}:///tmp/output2.csv"
85+
with fs.open(p2, "wb") as f:
86+
f.write(content)
87+
upath2 = UPath(p2, anon=self.anon, **self.s3so)
88+
assert upath2.read_bytes() == content
89+
upath2.unlink()

upath/tests/test_core.py

Lines changed: 6 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
import warnings
55

66
import pytest
7+
from fsspec.registry import get_filesystem_class
78

89
from upath import UPath
10+
from upath.tests.cases import BaseTests
911

1012

1113
@pytest.mark.skipif(
@@ -31,212 +33,18 @@ def test_UPath_warning():
3133
assert "mock" in str(w[-1].message)
3234

3335

34-
class TestUpath:
36+
37+
class TestUpath(BaseTests):
38+
3539
@pytest.fixture(autouse=True)
3640
def path(self, local_testdir):
3741
with warnings.catch_warnings():
3842
warnings.simplefilter("ignore")
3943
self.path = UPath(f"mock:{local_testdir}")
4044

41-
def test_cwd(self):
42-
with pytest.raises(NotImplementedError):
43-
self.path.cwd()
44-
45-
def test_home(self):
46-
with pytest.raises(NotImplementedError):
47-
self.path.home()
48-
49-
def test_stat(self):
50-
stat = self.path.stat()
51-
assert stat
52-
53-
def test_chmod(self):
54-
with pytest.raises(NotImplementedError):
55-
self.path.joinpath("file1.txt").chmod(777)
56-
57-
@pytest.mark.parametrize(
58-
"url, expected", [("file1.txt", True), ("fakefile.txt", False)]
59-
)
60-
def test_exists(self, url, expected):
61-
path = self.path.joinpath(url)
62-
assert path.exists() == expected
63-
64-
def test_expanduser(self):
65-
with pytest.raises(NotImplementedError):
66-
self.path.expanduser()
67-
68-
def test_glob(self, pathlib_base):
69-
mock_glob = list(self.path.glob("**.txt"))
70-
path_glob = list(pathlib_base.glob("**/*.txt"))
71-
72-
assert len(mock_glob) == len(path_glob)
73-
assert all(
74-
map(
75-
lambda m: m.path
76-
in [str(p).replace("\\", "/") for p in path_glob],
77-
mock_glob,
78-
)
79-
)
80-
81-
def test_group(self):
82-
with pytest.raises(NotImplementedError):
83-
self.path.group()
84-
85-
def test_is_dir(self):
86-
assert self.path.is_dir()
87-
88-
path = self.path.joinpath("file1.txt")
89-
assert not path.is_dir()
90-
91-
def test_is_file(self):
92-
path = self.path.joinpath("file1.txt")
93-
assert path.is_file()
94-
assert not self.path.is_file()
95-
96-
def test_is_mount(self):
97-
with pytest.raises(NotImplementedError):
98-
self.path.is_mount()
99-
100-
def test_is_symlink(self):
101-
with pytest.raises(NotImplementedError):
102-
self.path.is_symlink()
103-
104-
def test_is_socket(self):
105-
with pytest.raises(NotImplementedError):
106-
self.path.is_socket()
107-
108-
def test_is_fifo(self):
109-
with pytest.raises(NotImplementedError):
110-
self.path.is_fifo()
111-
112-
def test_is_block_device(self):
113-
with pytest.raises(NotImplementedError):
114-
self.path.is_block_device()
115-
116-
def test_is_char_device(self):
117-
with pytest.raises(NotImplementedError):
118-
self.path.is_char_device()
119-
120-
def test_iterdir(self, local_testdir):
121-
pl_path = Path(local_testdir)
122-
123-
up_iter = list(self.path.iterdir())
124-
pl_iter = list(pl_path.iterdir())
125-
126-
assert len(up_iter) == len(pl_iter)
127-
pnames = [p.name for p in pl_iter]
128-
assert all(map(lambda x: x.name in pnames, up_iter))
129-
130-
def test_lchmod(self):
131-
with pytest.raises(NotImplementedError):
132-
self.path.lchmod(mode=77)
133-
134-
def test_lstat(self):
135-
with pytest.raises(NotImplementedError):
136-
self.path.lstat()
137-
138-
def test_mkdir(self):
139-
new_dir = self.path.joinpath("new_dir")
140-
new_dir.mkdir()
141-
assert new_dir.exists()
142-
143-
def test_open(self):
45+
def test_fsspec_compat(self):
14446
pass
14547

146-
def test_owner(self):
147-
with pytest.raises(NotImplementedError):
148-
self.path.owner()
149-
150-
def test_read_bytes(self, pathlib_base):
151-
mock = self.path.joinpath("file2.txt")
152-
pl = pathlib_base.joinpath("file2.txt")
153-
assert mock.read_bytes() == pl.read_bytes()
154-
155-
def test_read_text(self, local_testdir):
156-
upath = self.path.joinpath("file1.txt")
157-
assert (
158-
upath.read_text()
159-
== Path(local_testdir).joinpath("file1.txt").read_text()
160-
)
161-
162-
def test_readlink(self):
163-
with pytest.raises(NotImplementedError):
164-
self.path.readlink()
165-
166-
@pytest.mark.xfail
167-
def test_rename(self):
168-
# need to impliment
169-
raise False
170-
171-
def test_replace(self):
172-
pass
173-
174-
def test_resolve(self):
175-
pass
176-
177-
def test_rglob(self):
178-
pass
179-
180-
def test_samefile(self):
181-
pass
182-
183-
def test_symlink_to(self):
184-
pass
185-
186-
def test_touch_unlink(self):
187-
path = self.path.joinpath("test_touch.txt")
188-
path.touch()
189-
assert path.exists()
190-
path.unlink()
191-
assert not path.exists()
192-
193-
# should raise FileNotFoundError since file is missing
194-
with pytest.raises(FileNotFoundError):
195-
path.unlink()
196-
197-
# file doesn't exists, but missing_ok is True
198-
path.unlink(missing_ok=True)
199-
200-
def test_link_to(self):
201-
pass
202-
203-
def test_write_bytes(self, pathlib_base):
204-
fn = "test_write_bytes.txt"
205-
s = b"hello_world"
206-
path = self.path.joinpath(fn)
207-
path.write_bytes(s)
208-
assert path.read_bytes() == s
209-
210-
def test_write_text(self, pathlib_base):
211-
fn = "test_write_text.txt"
212-
s = "hello_world"
213-
path = self.path.joinpath(fn)
214-
path.write_text(s)
215-
assert path.read_text() == s
216-
217-
def prepare_file_system(self):
218-
self.make_top_folder()
219-
self.make_test_files()
220-
221-
def make_top_folder(self):
222-
self.path.mkdir(parents=True, exist_ok=True)
223-
224-
def make_test_files(self):
225-
folder1 = self.path.joinpath("folder1")
226-
folder1.mkdir(exist_ok=True)
227-
folder1_files = ["file1.txt", "file2.txt"]
228-
for f in folder1_files:
229-
p = folder1.joinpath(f)
230-
p.touch()
231-
p.write_text(f)
232-
233-
file1 = self.path.joinpath("file1.txt")
234-
file1.touch()
235-
file1.write_text("hello world")
236-
file2 = self.path.joinpath("file2.txt")
237-
file2.touch()
238-
file2.write_bytes(b"hello world")
239-
24048

24149
@pytest.mark.hdfs
24250
def test_multiple_backend_paths(local_testdir, s3, hdfs):

upath/universal_path.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,9 @@ def _transform_arg_paths(self, args, kwargs):
4646
return args, kwargs
4747

4848
def _format_path(self, s):
49-
"""If the filesystem backend doesn't have a root_marker, strip the
50-
leading slash of a path
49+
"""placeholder method for subclassed filesystems
5150
"""
52-
if not self._fs.root_marker:
53-
return s.lstrip("/")
54-
else:
55-
return s
51+
return s
5652

5753
def __getattribute__(self, item):
5854
class_attrs = ["_url", "_fs", "__class__"]

0 commit comments

Comments
 (0)