1
1
import asyncio
2
2
import datetime
3
3
import logging
4
+ import ntpath
4
5
import os
6
+ import posixpath
5
7
import shutil
6
8
from functools import partial
7
9
from multiprocessing import cpu_count
11
13
Any ,
12
14
ClassVar ,
13
15
Dict ,
16
+ Iterable ,
14
17
Iterator ,
15
18
List ,
16
19
Literal ,
17
20
Optional ,
21
+ Sequence ,
18
22
Tuple ,
19
23
Union ,
20
24
cast ,
21
25
overload ,
22
26
)
27
+ from urllib .parse import urlsplit , urlunsplit
23
28
24
29
from fsspec .asyn import get_loop
25
30
40
45
41
46
from fsspec .spec import AbstractFileSystem
42
47
43
- from .path import Path
44
-
45
48
46
49
logger = logging .getLogger (__name__ )
47
50
@@ -68,6 +71,7 @@ def __init__(self, link: str, fs: "FileSystem", path: str) -> None:
68
71
class FileSystem :
69
72
sep = "/"
70
73
74
+ flavour = posixpath
71
75
protocol = "base"
72
76
REQUIRES : ClassVar [Dict [str , str ]] = {}
73
77
_JOBS = 4 * cpu_count ()
@@ -104,14 +108,138 @@ def config(self) -> Dict[str, Any]:
104
108
def root_marker (self ) -> str :
105
109
return self .fs .root_marker
106
110
107
- @cached_property
108
- def path (self ) -> "Path" :
109
- from .path import Path
111
+ def getcwd (self ) -> str :
112
+ return ""
113
+
114
+ def chdir (self , path : str ):
115
+ raise NotImplementedError
116
+
117
+ @classmethod
118
+ def join (cls , * parts : str ) -> str :
119
+ return cls .flavour .join (* parts )
120
+
121
+ @classmethod
122
+ def split (cls , path : str ) -> Tuple [str , str ]:
123
+ return cls .flavour .split (path )
124
+
125
+ @classmethod
126
+ def splitext (cls , path : str ) -> Tuple [str , str ]:
127
+ return cls .flavour .splitext (path )
128
+
129
+ def normpath (self , path : str ) -> str :
130
+ if self .flavour == ntpath :
131
+ return self .flavour .normpath (path )
132
+
133
+ parts = list (urlsplit (path ))
134
+ parts [2 ] = self .flavour .normpath (parts [2 ])
135
+ return urlunsplit (parts )
136
+
137
+ @classmethod
138
+ def isabs (cls , path : str ) -> bool :
139
+ return cls .flavour .isabs (path )
140
+
141
+ def abspath (self , path : str ) -> str :
142
+ if not self .isabs (path ):
143
+ path = self .join (self .getcwd (), path )
144
+ return self .normpath (path )
145
+
146
+ @classmethod
147
+ def commonprefix (cls , paths : Sequence [str ]) -> str :
148
+ return cls .flavour .commonprefix (paths )
149
+
150
+ @classmethod
151
+ def commonpath (cls , paths : Iterable [str ]) -> str :
152
+ return cls .flavour .commonpath (list (paths ))
153
+
154
+ @classmethod
155
+ def parts (cls , path : str ) -> Tuple [str , ...]:
156
+ drive , path = cls .flavour .splitdrive (path .rstrip (cls .flavour .sep ))
157
+
158
+ ret = []
159
+ while True :
160
+ path , part = cls .flavour .split (path )
161
+
162
+ if part :
163
+ ret .append (part )
164
+ continue
165
+
166
+ if path :
167
+ ret .append (path )
168
+
169
+ break
170
+
171
+ ret .reverse ()
172
+
173
+ if drive :
174
+ ret = [drive , * ret ]
110
175
111
- def _getcwd ():
112
- return self .fs .root_marker
176
+ return tuple (ret )
113
177
114
- return Path (self .sep , getcwd = _getcwd )
178
+ @classmethod
179
+ def parent (cls , path : str ) -> str :
180
+ return cls .flavour .dirname (path )
181
+
182
+ @classmethod
183
+ def dirname (cls , path : str ) -> str :
184
+ return cls .parent (path )
185
+
186
+ @classmethod
187
+ def parents (cls , path : str ) -> Iterator [str ]:
188
+ while True :
189
+ parent = cls .flavour .dirname (path )
190
+ if parent == path :
191
+ break
192
+ yield parent
193
+ path = parent
194
+
195
+ @classmethod
196
+ def name (cls , path : str ) -> str :
197
+ return cls .flavour .basename (path )
198
+
199
+ @classmethod
200
+ def suffix (cls , path : str ) -> str :
201
+ name = cls .name (path )
202
+ _ , dot , suffix = name .partition ("." )
203
+ return dot + suffix
204
+
205
+ @classmethod
206
+ def with_name (cls , path : str , name : str ) -> str :
207
+ return cls .join (cls .parent (path ), name )
208
+
209
+ @classmethod
210
+ def with_suffix (cls , path : str , suffix : str ) -> str :
211
+ return cls .splitext (path )[0 ] + suffix
212
+
213
+ @classmethod
214
+ def isin (cls , left : str , right : str ) -> bool :
215
+ if left == right :
216
+ return False
217
+ try :
218
+ common = cls .commonpath ([left , right ])
219
+ except ValueError :
220
+ # Paths don't have the same drive
221
+ return False
222
+ return common == right
223
+
224
+ @classmethod
225
+ def isin_or_eq (cls , left : str , right : str ) -> bool :
226
+ return left == right or cls .isin (left , right )
227
+
228
+ @classmethod
229
+ def overlaps (cls , left : str , right : str ) -> bool :
230
+ return cls .isin_or_eq (left , right ) or cls .isin (right , left )
231
+
232
+ def relpath (self , path : str , start : Optional [str ] = None ) -> str :
233
+ if start is None :
234
+ start = "."
235
+ return self .flavour .relpath (self .abspath (path ), start = self .abspath (start ))
236
+
237
+ def relparts (self , path : str , start : Optional [str ] = None ) -> Tuple [str , ...]:
238
+ return self .parts (self .relpath (path , start = start ))
239
+
240
+ @classmethod
241
+ def as_posix (cls , path : str ) -> str :
242
+ return path .replace (cls .flavour .sep , posixpath .sep )
115
243
116
244
@classmethod
117
245
def _strip_protocol (cls , path : str ) -> str :
@@ -299,7 +427,7 @@ def checksum(self, path: AnyFSPath) -> str:
299
427
return self .fs .checksum (path )
300
428
301
429
def copy (self , from_info : AnyFSPath , to_info : AnyFSPath ) -> None :
302
- self .makedirs (self .path . parent (to_info ))
430
+ self .makedirs (self .parent (to_info ))
303
431
self .fs .copy (from_info , to_info )
304
432
305
433
def cp_file (self , from_info : AnyFSPath , to_info : AnyFSPath , ** kwargs : Any ) -> None :
@@ -515,7 +643,7 @@ def put_file(
515
643
else :
516
644
assert isinstance (from_file , str )
517
645
self .fs .put_file (os .fspath (from_file ), to_info , callback = callback , ** kwargs )
518
- self .fs .invalidate_cache (self .path . parent (to_info ))
646
+ self .fs .invalidate_cache (self .parent (to_info ))
519
647
520
648
def get_file (
521
649
self ,
@@ -527,7 +655,7 @@ def get_file(
527
655
self .fs .get_file (from_info , to_info , callback = callback , ** kwargs )
528
656
529
657
def upload_fobj (self , fobj : IO , to_info : AnyFSPath , ** kwargs ) -> None :
530
- self .makedirs (self .path . parent (to_info ))
658
+ self .makedirs (self .parent (to_info ))
531
659
with self .open (to_info , "wb" ) as fdest :
532
660
shutil .copyfileobj (
533
661
fobj ,
@@ -597,7 +725,7 @@ def get(
597
725
from .local import localfs
598
726
599
727
def get_file (rpath , lpath , ** kwargs ):
600
- localfs .makedirs (localfs .path . parent (lpath ), exist_ok = True )
728
+ localfs .makedirs (localfs .parent (lpath ), exist_ok = True )
601
729
self .fs .get_file (rpath , lpath , ** kwargs )
602
730
603
731
get_file = wrap_and_branch_callback (callback , get_file )
@@ -618,7 +746,7 @@ def get_file(rpath, lpath, **kwargs):
618
746
return localfs .makedirs (to_info , exist_ok = True )
619
747
620
748
to_infos = [
621
- localfs .path . join (to_info , * self . path .relparts (info , from_info ))
749
+ localfs .join (to_info , * self .relparts (info , from_info ))
622
750
for info in from_infos
623
751
]
624
752
@@ -679,9 +807,9 @@ def find(
679
807
680
808
def _make_args (paths : List [AnyFSPath ]) -> Iterator [Tuple [str , str ]]:
681
809
for path in paths :
682
- if prefix and not path .endswith (self .path . flavour .sep ):
683
- parent = self .path . parent (path )
684
- yield parent , self .path . parts (path )[- 1 ]
810
+ if prefix and not path .endswith (self .flavour .sep ):
811
+ parent = self .parent (path )
812
+ yield parent , self .parts (path )[- 1 ]
685
813
else :
686
814
yield path , ""
687
815
0 commit comments