Skip to content

Commit 62e1c3d

Browse files
authored
Fix webdav tests (fsspec#107)
* vendor test.os_support in tests.utils * tests: modify webdav-fixture to improve behavior on windows
1 parent 0f5f418 commit 62e1c3d

File tree

3 files changed

+134
-4
lines changed

3 files changed

+134
-4
lines changed

.flake8

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ count = true
1717
per-file-ignores =
1818
upath/__init__.py: F401
1919
upath/tests/test_pathlib.py: E127,E128,E201,E202,E203,E225,E255,E302,E303,E306,E401,E402,E501,E731
20+
upath/tests/utils.py: C901
2021
exclude =
2122
.noxfile,
2223
.nox,

upath/tests/conftest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from fsspec.registry import register_implementation
1616

1717
from .utils import posixify
18+
from .utils import rmtree
1819

1920

2021
class DummyTestFS(LocalFileSystem):
@@ -314,13 +315,12 @@ def webdav_server(tmp_path_factory):
314315
@pytest.fixture
315316
def webdav_fixture(local_testdir, webdav_server):
316317
webdav_path, webdav_url = webdav_server
317-
if os.path.isdir(webdav_path):
318-
shutil.rmtree(webdav_path, ignore_errors=True)
319318
try:
320-
shutil.copytree(local_testdir, webdav_path)
319+
shutil.copytree(local_testdir, webdav_path, dirs_exist_ok=True)
321320
yield webdav_url
322321
finally:
323-
shutil.rmtree(webdav_path, ignore_errors=True)
322+
rmtree(webdav_path)
323+
os.mkdir(webdav_path, mode=0o700)
324324

325325

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

upath/tests/utils.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
import os
2+
import stat
13
import sys
4+
import time
5+
import warnings
26

37
import pytest
48

@@ -17,3 +21,128 @@ def only_on_windows(func):
1721

1822
def posixify(path):
1923
return str(path).replace("\\", "/")
24+
25+
26+
# === vendored from test.os_support ===========================================
27+
# https://github.com/python/cpython/blob/7f97c8e36786/Lib/test/support/os_helper.py#LL327C1-L445C1
28+
# fmt: off
29+
if sys.platform.startswith("win"):
30+
def _waitfor(func, pathname, waitall=False):
31+
# Perform the operation
32+
func(pathname)
33+
# Now setup the wait loop
34+
if waitall:
35+
dirname = pathname
36+
else:
37+
dirname, name = os.path.split(pathname)
38+
dirname = dirname or '.'
39+
# Check for `pathname` to be removed from the filesystem.
40+
# The exponential backoff of the timeout amounts to a total
41+
# of ~1 second after which the deletion is probably an error
42+
# anyway.
43+
# Testing on an [email protected] shows that usually only 1 iteration is
44+
# required when contention occurs.
45+
timeout = 0.001
46+
while timeout < 1.0:
47+
# Note we are only testing for the existence of the file(s) in
48+
# the contents of the directory regardless of any security or
49+
# access rights. If we have made it this far, we have sufficient
50+
# permissions to do that much using Python's equivalent of the
51+
# Windows API FindFirstFile.
52+
# Other Windows APIs can fail or give incorrect results when
53+
# dealing with files that are pending deletion.
54+
L = os.listdir(dirname)
55+
if not (L if waitall else name in L):
56+
return
57+
# Increase the timeout and try again
58+
time.sleep(timeout)
59+
timeout *= 2
60+
warnings.warn('tests may fail, delete still pending for ' + pathname,
61+
RuntimeWarning, stacklevel=4)
62+
63+
def _unlink(filename):
64+
_waitfor(os.unlink, filename)
65+
66+
def _rmdir(dirname):
67+
_waitfor(os.rmdir, dirname)
68+
69+
def _rmtree(path):
70+
from test.support import _force_run
71+
72+
def _rmtree_inner(path):
73+
for name in _force_run(path, os.listdir, path):
74+
fullname = os.path.join(path, name)
75+
try:
76+
mode = os.lstat(fullname).st_mode
77+
except OSError as exc:
78+
print("support.rmtree(): os.lstat(%r) failed with %s"
79+
% (fullname, exc),
80+
file=sys.__stderr__)
81+
mode = 0
82+
if stat.S_ISDIR(mode):
83+
_waitfor(_rmtree_inner, fullname, waitall=True)
84+
_force_run(fullname, os.rmdir, fullname)
85+
else:
86+
_force_run(fullname, os.unlink, fullname)
87+
_waitfor(_rmtree_inner, path, waitall=True)
88+
_waitfor(lambda p: _force_run(p, os.rmdir, p), path)
89+
90+
def _longpath(path):
91+
try:
92+
import ctypes
93+
except ImportError:
94+
# No ctypes means we can't expands paths.
95+
pass
96+
else:
97+
buffer = ctypes.create_unicode_buffer(len(path) * 2)
98+
length = ctypes.windll.kernel32.GetLongPathNameW(path, buffer,
99+
len(buffer))
100+
if length:
101+
return buffer[:length]
102+
return path
103+
else:
104+
_unlink = os.unlink
105+
_rmdir = os.rmdir
106+
107+
def _rmtree(path):
108+
import shutil
109+
try:
110+
shutil.rmtree(path)
111+
return
112+
except OSError:
113+
pass
114+
115+
def _rmtree_inner(path):
116+
from test.support import _force_run
117+
for name in _force_run(path, os.listdir, path):
118+
fullname = os.path.join(path, name)
119+
try:
120+
mode = os.lstat(fullname).st_mode
121+
except OSError:
122+
mode = 0
123+
if stat.S_ISDIR(mode):
124+
_rmtree_inner(fullname)
125+
_force_run(path, os.rmdir, fullname)
126+
else:
127+
_force_run(path, os.unlink, fullname)
128+
_rmtree_inner(path)
129+
os.rmdir(path)
130+
131+
def _longpath(path):
132+
return path
133+
134+
135+
def rmdir(dirname):
136+
try:
137+
_rmdir(dirname)
138+
except FileNotFoundError:
139+
pass
140+
141+
142+
def rmtree(path):
143+
try:
144+
_rmtree(path)
145+
except FileNotFoundError:
146+
pass
147+
# fmt: on
148+
# === /vendored from test.os_support ==========================================

0 commit comments

Comments
 (0)