Skip to content

Commit da77548

Browse files
authored
LocalFileSystem restore _strip_protocol signature (#1567)
1 parent bc40f36 commit da77548

File tree

5 files changed

+373
-67
lines changed

5 files changed

+373
-67
lines changed

ci/environment-py38.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ channels:
33
- conda-forge
44
dependencies:
55
- pip
6-
- git
6+
- git <2.45.0
77
- py
88
- pip:
99
- hadoop-test-cluster

fsspec/implementations/local.py

+77-44
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,6 @@
1515
logger = logging.getLogger("fsspec.local")
1616

1717

18-
def _remove_prefix(text: str, prefix: str):
19-
if text.startswith(prefix):
20-
return text[len(prefix) :]
21-
return text
22-
23-
2418
class LocalFileSystem(AbstractFileSystem):
2519
"""Interface to files on local storage
2620
@@ -121,8 +115,8 @@ def lexists(self, path, **kwargs):
121115
return osp.lexists(path)
122116

123117
def cp_file(self, path1, path2, **kwargs):
124-
path1 = self._strip_protocol(path1, remove_trailing_slash=True)
125-
path2 = self._strip_protocol(path2, remove_trailing_slash=True)
118+
path1 = self._strip_protocol(path1)
119+
path2 = self._strip_protocol(path2)
126120
if self.auto_mkdir:
127121
self.makedirs(self._parent(path2), exist_ok=True)
128122
if self.isfile(path1):
@@ -151,8 +145,8 @@ def put_file(self, path1, path2, callback=None, **kwargs):
151145
return self.cp_file(path1, path2, **kwargs)
152146

153147
def mv(self, path1, path2, **kwargs):
154-
path1 = self._strip_protocol(path1, remove_trailing_slash=True)
155-
path2 = self._strip_protocol(path2, remove_trailing_slash=True)
148+
path1 = self._strip_protocol(path1)
149+
path2 = self._strip_protocol(path2)
156150
shutil.move(path1, path2)
157151

158152
def link(self, src, dst, **kwargs):
@@ -176,7 +170,7 @@ def rm(self, path, recursive=False, maxdepth=None):
176170
path = [path]
177171

178172
for p in path:
179-
p = self._strip_protocol(p, remove_trailing_slash=True)
173+
p = self._strip_protocol(p)
180174
if self.isdir(p):
181175
if not recursive:
182176
raise ValueError("Cannot delete directory, set recursive=True")
@@ -219,7 +213,7 @@ def modified(self, path):
219213

220214
@classmethod
221215
def _parent(cls, path):
222-
path = cls._strip_protocol(path, remove_trailing_slash=True)
216+
path = cls._strip_protocol(path)
223217
if os.sep == "/":
224218
# posix native
225219
return path.rsplit("/", 1)[0] or "/"
@@ -234,17 +228,43 @@ def _parent(cls, path):
234228
return path_
235229

236230
@classmethod
237-
def _strip_protocol(cls, path, remove_trailing_slash=False):
231+
def _strip_protocol(cls, path):
238232
path = stringify_path(path)
239-
if path.startswith("file:"):
240-
path = _remove_prefix(_remove_prefix(path, "file://"), "file:")
241-
if os.sep == "\\":
242-
path = path.lstrip("/")
233+
if path.startswith("file://"):
234+
path = path[7:]
235+
elif path.startswith("file:"):
236+
path = path[5:]
237+
elif path.startswith("local://"):
238+
path = path[8:]
243239
elif path.startswith("local:"):
244-
path = _remove_prefix(_remove_prefix(path, "local://"), "local:")
245-
if os.sep == "\\":
246-
path = path.lstrip("/")
247-
return make_path_posix(path, remove_trailing_slash)
240+
path = path[6:]
241+
242+
path = make_path_posix(path)
243+
if os.sep != "/":
244+
# This code-path is a stripped down version of
245+
# > drive, path = ntpath.splitdrive(path)
246+
if path[1:2] == ":":
247+
# Absolute drive-letter path, e.g. X:\Windows
248+
# Relative path with drive, e.g. X:Windows
249+
drive, path = path[:2], path[2:]
250+
elif path[:2] == "//":
251+
# UNC drives, e.g. \\server\share or \\?\UNC\server\share
252+
# Device drives, e.g. \\.\device or \\?\device
253+
if (index1 := path.find("/", 2)) == -1 or (
254+
index2 := path.find("/", index1 + 1)
255+
) == -1:
256+
drive, path = path, ""
257+
else:
258+
drive, path = path[:index2], path[index2:]
259+
else:
260+
# Relative path, e.g. Windows
261+
drive = ""
262+
263+
path = path.rstrip("/") or cls.root_marker
264+
return drive + path
265+
266+
else:
267+
return path.rstrip("/") or cls.root_marker
248268

249269
def _isfilestore(self):
250270
# Inheriting from DaskFileSystem makes this False (S3, etc. were)
@@ -257,42 +277,55 @@ def chmod(self, path, mode):
257277
return os.chmod(path, mode)
258278

259279

260-
def make_path_posix(path, remove_trailing_slash=False):
261-
"""Make path generic for current OS"""
280+
def make_path_posix(path):
281+
"""Make path generic and absolute for current OS"""
262282
if not isinstance(path, str):
263283
if isinstance(path, (list, set, tuple)):
264-
return type(path)(make_path_posix(p, remove_trailing_slash) for p in path)
284+
return type(path)(make_path_posix(p) for p in path)
265285
else:
266-
path = str(stringify_path(path))
286+
path = stringify_path(path)
287+
if not isinstance(path, str):
288+
raise TypeError(f"could not convert {path!r} to string")
267289
if os.sep == "/":
268290
# Native posix
269291
if path.startswith("/"):
270292
# most common fast case for posix
271-
return path.rstrip("/") or "/" if remove_trailing_slash else path
293+
return path
272294
elif path.startswith("~"):
273-
return make_path_posix(osp.expanduser(path), remove_trailing_slash)
295+
return osp.expanduser(path)
274296
elif path.startswith("./"):
275297
path = path[2:]
276-
path = f"{os.getcwd()}/{path}"
277-
return path.rstrip("/") or "/" if remove_trailing_slash else path
298+
elif path == ".":
299+
path = ""
278300
return f"{os.getcwd()}/{path}"
279301
else:
280302
# NT handling
281-
if len(path) > 1:
282-
if path[1] == ":":
283-
# windows full path like "C:\\local\\path"
284-
if len(path) <= 3:
285-
# nt root (something like c:/)
286-
return path[0] + ":/"
287-
path = path.replace("\\", "/").replace("//", "/")
288-
return path.rstrip("/") if remove_trailing_slash else path
289-
elif path[0] == "~":
290-
return make_path_posix(osp.expanduser(path), remove_trailing_slash)
291-
elif path.startswith(("\\\\", "//")):
292-
# windows UNC/DFS-style paths
293-
path = "//" + path[2:].replace("\\", "/").replace("//", "/")
294-
return path.rstrip("/") if remove_trailing_slash else path
295-
return make_path_posix(osp.abspath(path), remove_trailing_slash)
303+
if path[0:1] == "/" and path[2:3] == ":":
304+
# path is like "/c:/local/path"
305+
path = path[1:]
306+
if path[1:2] == ":":
307+
# windows full path like "C:\\local\\path"
308+
if len(path) <= 3:
309+
# nt root (something like c:/)
310+
return path[0] + ":/"
311+
path = path.replace("\\", "/")
312+
return path
313+
elif path[0:1] == "~":
314+
return make_path_posix(osp.expanduser(path))
315+
elif path.startswith(("\\\\", "//")):
316+
# windows UNC/DFS-style paths
317+
return "//" + path[2:].replace("\\", "/")
318+
elif path.startswith(("\\", "/")):
319+
# windows relative path with root
320+
path = path.replace("\\", "/")
321+
return f"{osp.splitdrive(os.getcwd())[0]}{path}"
322+
else:
323+
path = path.replace("\\", "/")
324+
if path.startswith("./"):
325+
path = path[2:]
326+
elif path == ".":
327+
path = ""
328+
return f"{make_path_posix(os.getcwd())}/{path}"
296329

297330

298331
def trailing_sep(path):

0 commit comments

Comments
 (0)