megfile 4.2.4__py3-none-any.whl → 5.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- megfile/__init__.py +16 -291
- megfile/cli.py +37 -20
- megfile/config.py +10 -1
- megfile/errors.py +2 -2
- megfile/fs_path.py +78 -12
- megfile/interfaces.py +44 -0
- megfile/lib/base_memory_handler.py +92 -0
- megfile/lib/glob.py +3 -3
- megfile/lib/http_prefetch_reader.py +22 -22
- megfile/lib/joinpath.py +13 -0
- megfile/lib/s3_buffered_writer.py +13 -0
- megfile/lib/s3_limited_seekable_writer.py +2 -0
- megfile/lib/s3_memory_handler.py +14 -81
- megfile/lib/webdav_memory_handler.py +83 -0
- megfile/lib/webdav_prefetch_reader.py +115 -0
- megfile/pathlike.py +3 -4
- megfile/s3_path.py +44 -33
- megfile/sftp2_path.py +44 -62
- megfile/sftp_path.py +239 -2
- megfile/smart.py +70 -29
- megfile/smart_path.py +181 -85
- megfile/version.py +1 -1
- megfile/webdav_path.py +952 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/METADATA +30 -39
- megfile-5.0.0.dist-info/RECORD +51 -0
- megfile/fs.py +0 -614
- megfile/hdfs.py +0 -408
- megfile/http.py +0 -114
- megfile/s3.py +0 -540
- megfile/sftp.py +0 -821
- megfile/sftp2.py +0 -827
- megfile/stdio.py +0 -30
- megfile-4.2.4.dist-info/RECORD +0 -54
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/WHEEL +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/entry_points.txt +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/licenses/LICENSE +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/licenses/LICENSE.pyre +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/top_level.txt +0 -0
megfile/fs.py
DELETED
|
@@ -1,614 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from stat import S_ISDIR as stat_isdir
|
|
3
|
-
from stat import S_ISLNK as stat_islnk
|
|
4
|
-
from typing import BinaryIO, Callable, Iterator, List, Optional, Tuple
|
|
5
|
-
|
|
6
|
-
from megfile.fs_path import (
|
|
7
|
-
FSPath,
|
|
8
|
-
_make_stat,
|
|
9
|
-
fs_path_join,
|
|
10
|
-
is_fs,
|
|
11
|
-
)
|
|
12
|
-
from megfile.interfaces import Access, ContextIterator, FileEntry, PathLike, StatResult
|
|
13
|
-
|
|
14
|
-
__all__ = [
|
|
15
|
-
"is_fs",
|
|
16
|
-
"fs_path_join",
|
|
17
|
-
"fs_readlink",
|
|
18
|
-
"fs_cwd",
|
|
19
|
-
"fs_home",
|
|
20
|
-
"fs_iglob",
|
|
21
|
-
"fs_glob",
|
|
22
|
-
"fs_glob_stat",
|
|
23
|
-
"fs_rename",
|
|
24
|
-
"fs_resolve",
|
|
25
|
-
"fs_move",
|
|
26
|
-
"fs_makedirs",
|
|
27
|
-
"fs_lstat",
|
|
28
|
-
"fs_isabs",
|
|
29
|
-
"fs_abspath",
|
|
30
|
-
"fs_access",
|
|
31
|
-
"fs_exists",
|
|
32
|
-
"fs_getmtime",
|
|
33
|
-
"fs_getsize",
|
|
34
|
-
"fs_expanduser",
|
|
35
|
-
"fs_isdir",
|
|
36
|
-
"fs_isfile",
|
|
37
|
-
"fs_listdir",
|
|
38
|
-
"fs_load_from",
|
|
39
|
-
"fs_realpath",
|
|
40
|
-
"fs_relpath",
|
|
41
|
-
"fs_remove",
|
|
42
|
-
"fs_scan",
|
|
43
|
-
"fs_scan_stat",
|
|
44
|
-
"fs_scandir",
|
|
45
|
-
"fs_stat",
|
|
46
|
-
"fs_unlink",
|
|
47
|
-
"fs_walk",
|
|
48
|
-
"fs_getmd5",
|
|
49
|
-
"fs_copy",
|
|
50
|
-
"fs_sync",
|
|
51
|
-
"fs_symlink",
|
|
52
|
-
"fs_islink",
|
|
53
|
-
"fs_ismount",
|
|
54
|
-
"fs_save_as",
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def fs_isabs(path: PathLike) -> bool:
|
|
59
|
-
"""Test whether a path is absolute
|
|
60
|
-
|
|
61
|
-
:param path: Given path
|
|
62
|
-
:returns: True if a path is absolute, else False
|
|
63
|
-
"""
|
|
64
|
-
return FSPath(path).is_absolute()
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def fs_abspath(path: PathLike) -> str:
|
|
68
|
-
"""Return the absolute path of given path
|
|
69
|
-
|
|
70
|
-
:param path: Given path
|
|
71
|
-
:returns: Absolute path of given path
|
|
72
|
-
"""
|
|
73
|
-
return FSPath(path).abspath()
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def fs_access(path: PathLike, mode: Access = Access.READ) -> bool:
|
|
77
|
-
"""
|
|
78
|
-
Test if path has access permission described by mode
|
|
79
|
-
Using ``os.access``
|
|
80
|
-
|
|
81
|
-
:param path: Given path
|
|
82
|
-
:param mode: access mode
|
|
83
|
-
:returns: Access: Enum, the read/write access that path has.
|
|
84
|
-
"""
|
|
85
|
-
return FSPath(path).access(mode)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def fs_exists(path: PathLike, followlinks: bool = False) -> bool:
|
|
89
|
-
"""
|
|
90
|
-
Test if the path exists
|
|
91
|
-
|
|
92
|
-
.. note::
|
|
93
|
-
|
|
94
|
-
The difference between this function and ``os.path.exists`` is that
|
|
95
|
-
this function regard symlink as file.
|
|
96
|
-
In other words, this function is equal to ``os.path.lexists``
|
|
97
|
-
|
|
98
|
-
:param path: Given path
|
|
99
|
-
:param followlinks: False if regard symlink as file, else True
|
|
100
|
-
:returns: True if the path exists, else False
|
|
101
|
-
|
|
102
|
-
"""
|
|
103
|
-
return FSPath(path).exists(followlinks)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def fs_getmtime(path: PathLike, follow_symlinks: bool = False) -> float:
|
|
107
|
-
"""
|
|
108
|
-
Get last-modified time of the file on the given path (in Unix timestamp format).
|
|
109
|
-
If the path is an existent directory,
|
|
110
|
-
return the latest modified time of all file in it.
|
|
111
|
-
|
|
112
|
-
:param path: Given path
|
|
113
|
-
:returns: last-modified time
|
|
114
|
-
"""
|
|
115
|
-
return FSPath(path).getmtime(follow_symlinks)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def fs_getsize(path: PathLike, follow_symlinks: bool = False) -> int:
|
|
119
|
-
"""
|
|
120
|
-
Get file size on the given file path (in bytes).
|
|
121
|
-
If the path in a directory, return the sum of all file size in it,
|
|
122
|
-
including file in subdirectories (if exist).
|
|
123
|
-
The result excludes the size of directory itself.
|
|
124
|
-
In other words, return 0 Byte on an empty directory path.
|
|
125
|
-
|
|
126
|
-
:param path: Given path
|
|
127
|
-
:returns: File size
|
|
128
|
-
|
|
129
|
-
"""
|
|
130
|
-
return FSPath(path).getsize(follow_symlinks)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def fs_expanduser(path: PathLike):
|
|
134
|
-
"""Expand ~ and ~user constructions. If user or $HOME is unknown,
|
|
135
|
-
do nothing.
|
|
136
|
-
"""
|
|
137
|
-
return FSPath(path).expanduser()
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def fs_isdir(path: PathLike, followlinks: bool = False) -> bool:
|
|
141
|
-
"""
|
|
142
|
-
Test if a path is directory
|
|
143
|
-
|
|
144
|
-
.. note::
|
|
145
|
-
|
|
146
|
-
The difference between this function and ``os.path.isdir`` is that
|
|
147
|
-
this function regard symlink as file
|
|
148
|
-
|
|
149
|
-
:param path: Given path
|
|
150
|
-
:param followlinks: False if regard symlink as file, else True
|
|
151
|
-
:returns: True if the path is a directory, else False
|
|
152
|
-
|
|
153
|
-
"""
|
|
154
|
-
return FSPath(path).is_dir(followlinks)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def fs_isfile(path: PathLike, followlinks: bool = False) -> bool:
|
|
158
|
-
"""
|
|
159
|
-
Test if a path is file
|
|
160
|
-
|
|
161
|
-
.. note::
|
|
162
|
-
|
|
163
|
-
The difference between this function and ``os.path.isfile`` is that
|
|
164
|
-
this function regard symlink as file
|
|
165
|
-
|
|
166
|
-
:param path: Given path
|
|
167
|
-
:param followlinks: False if regard symlink as file, else True
|
|
168
|
-
:returns: True if the path is a file, else False
|
|
169
|
-
|
|
170
|
-
"""
|
|
171
|
-
return FSPath(path).is_file(followlinks)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def fs_listdir(path: Optional[PathLike] = None) -> List[str]:
|
|
175
|
-
"""
|
|
176
|
-
Get all contents of given fs path.
|
|
177
|
-
The result is in ascending alphabetical order.
|
|
178
|
-
|
|
179
|
-
:param path: Given path
|
|
180
|
-
:returns: All contents have in the path in ascending alphabetical order
|
|
181
|
-
"""
|
|
182
|
-
if path is None:
|
|
183
|
-
return sorted(os.listdir(path))
|
|
184
|
-
return FSPath(path).listdir()
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def fs_load_from(path: PathLike) -> BinaryIO:
|
|
188
|
-
"""Read all content on specified path and write into memory
|
|
189
|
-
|
|
190
|
-
User should close the BinaryIO manually
|
|
191
|
-
|
|
192
|
-
:param path: Given path
|
|
193
|
-
:returns: Binary stream
|
|
194
|
-
"""
|
|
195
|
-
return FSPath(path).load()
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
def fs_realpath(path: PathLike) -> str:
|
|
199
|
-
"""Return the real path of given path
|
|
200
|
-
|
|
201
|
-
:param path: Given path
|
|
202
|
-
:returns: Real path of given path
|
|
203
|
-
"""
|
|
204
|
-
return FSPath(path).realpath()
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def fs_relpath(path: PathLike, start: Optional[str] = None) -> str:
|
|
208
|
-
"""Return the relative path of given path
|
|
209
|
-
|
|
210
|
-
:param path: Given path
|
|
211
|
-
:param start: Given start directory
|
|
212
|
-
:returns: Relative path from start
|
|
213
|
-
"""
|
|
214
|
-
return FSPath(path).relpath(start)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def fs_remove(path: PathLike, missing_ok: bool = False) -> None:
|
|
218
|
-
"""
|
|
219
|
-
Remove the file or directory on fs
|
|
220
|
-
|
|
221
|
-
:param path: Given path
|
|
222
|
-
:param missing_ok: if False and target file/directory not exists,
|
|
223
|
-
raise FileNotFoundError
|
|
224
|
-
"""
|
|
225
|
-
return FSPath(path).remove(missing_ok)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
def fs_scan(
|
|
229
|
-
path: PathLike, missing_ok: bool = True, followlinks: bool = False
|
|
230
|
-
) -> Iterator[str]:
|
|
231
|
-
"""
|
|
232
|
-
Iteratively traverse only files in given directory, in alphabetical order.
|
|
233
|
-
Every iteration on generator yields a path string.
|
|
234
|
-
|
|
235
|
-
If path is a file path, yields the file only
|
|
236
|
-
If path is a non-existent path, return an empty generator
|
|
237
|
-
If path is a bucket path, return all file paths in the bucket
|
|
238
|
-
|
|
239
|
-
:param path: Given path
|
|
240
|
-
:param missing_ok: If False and there's no file in the directory,
|
|
241
|
-
raise FileNotFoundError
|
|
242
|
-
:returns: A file path generator
|
|
243
|
-
"""
|
|
244
|
-
return FSPath(path).scan(missing_ok, followlinks)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def fs_scan_stat(
|
|
248
|
-
path: PathLike, missing_ok: bool = True, followlinks: bool = False
|
|
249
|
-
) -> Iterator[FileEntry]:
|
|
250
|
-
"""
|
|
251
|
-
Iteratively traverse only files in given directory, in alphabetical order.
|
|
252
|
-
Every iteration on generator yields a tuple of path string and file stat
|
|
253
|
-
|
|
254
|
-
:param path: Given path
|
|
255
|
-
:param missing_ok: If False and there's no file in the directory,
|
|
256
|
-
raise FileNotFoundError
|
|
257
|
-
:returns: A file path generator
|
|
258
|
-
"""
|
|
259
|
-
return FSPath(path).scan_stat(missing_ok, followlinks)
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
def fs_scandir(path: Optional[PathLike] = None) -> Iterator[FileEntry]:
|
|
263
|
-
"""
|
|
264
|
-
Get all content of given file path.
|
|
265
|
-
|
|
266
|
-
:param path: Given path
|
|
267
|
-
:returns: An iterator contains all contents have prefix path
|
|
268
|
-
"""
|
|
269
|
-
if path is None:
|
|
270
|
-
|
|
271
|
-
def create_generator():
|
|
272
|
-
with os.scandir(None) as entries:
|
|
273
|
-
for entry in entries:
|
|
274
|
-
stat = entry.stat()
|
|
275
|
-
yield FileEntry(
|
|
276
|
-
entry.name,
|
|
277
|
-
entry.path,
|
|
278
|
-
StatResult(
|
|
279
|
-
size=stat.st_size,
|
|
280
|
-
ctime=stat.st_ctime,
|
|
281
|
-
mtime=stat.st_mtime,
|
|
282
|
-
isdir=stat_isdir(stat.st_mode),
|
|
283
|
-
islnk=stat_islnk(stat.st_mode),
|
|
284
|
-
extra=stat,
|
|
285
|
-
),
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
return ContextIterator(create_generator())
|
|
289
|
-
|
|
290
|
-
return FSPath(path).scandir()
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
def fs_stat(path: PathLike, follow_symlinks=True) -> StatResult:
|
|
294
|
-
"""
|
|
295
|
-
Get StatResult of file on fs, including file size and mtime,
|
|
296
|
-
referring to fs_getsize and fs_getmtime
|
|
297
|
-
|
|
298
|
-
:param path: Given path
|
|
299
|
-
:returns: StatResult
|
|
300
|
-
"""
|
|
301
|
-
return FSPath(path).stat(follow_symlinks)
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
def fs_unlink(path: PathLike, missing_ok: bool = False) -> None:
|
|
305
|
-
"""
|
|
306
|
-
Remove the file on fs
|
|
307
|
-
|
|
308
|
-
:param path: Given path
|
|
309
|
-
:param missing_ok: if False and target file not exists, raise FileNotFoundError
|
|
310
|
-
"""
|
|
311
|
-
return FSPath(path).unlink(missing_ok)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
def fs_walk(
|
|
315
|
-
path: PathLike, followlinks: bool = False
|
|
316
|
-
) -> Iterator[Tuple[str, List[str], List[str]]]:
|
|
317
|
-
"""
|
|
318
|
-
Generate the file names in a directory tree by walking the tree top-down.
|
|
319
|
-
For each directory in the tree rooted at directory path (including path itself),
|
|
320
|
-
it yields a 3-tuple (root, dirs, files).
|
|
321
|
-
|
|
322
|
-
- root: a string of current path
|
|
323
|
-
- dirs: name list of subdirectories (excluding '.' and '..' if they exist)
|
|
324
|
-
in 'root'. The list is sorted by ascending alphabetical order
|
|
325
|
-
- files: name list of non-directory files (link is regarded as file) in 'root'.
|
|
326
|
-
The list is sorted by ascending alphabetical order
|
|
327
|
-
|
|
328
|
-
If path not exists, or path is a file (link is regarded as file),
|
|
329
|
-
return an empty generator
|
|
330
|
-
|
|
331
|
-
.. note::
|
|
332
|
-
|
|
333
|
-
Be aware that setting ``followlinks`` to True can lead to infinite recursion
|
|
334
|
-
if a link points to a parent directory of itself. fs_walk() does not keep
|
|
335
|
-
track of the directories it visited already.
|
|
336
|
-
|
|
337
|
-
:param path: Given path
|
|
338
|
-
:param followlinks: False if regard symlink as file, else True
|
|
339
|
-
|
|
340
|
-
:returns: A 3-tuple generator
|
|
341
|
-
"""
|
|
342
|
-
return FSPath(path).walk(followlinks)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def fs_getmd5(path: PathLike, recalculate: bool = False, followlinks: bool = False):
|
|
346
|
-
"""
|
|
347
|
-
Calculate the md5 value of the file
|
|
348
|
-
|
|
349
|
-
:param path: Given path
|
|
350
|
-
:param recalculate: Ignore this parameter, just for compatibility
|
|
351
|
-
:param followlinks: Ignore this parameter, just for compatibility
|
|
352
|
-
|
|
353
|
-
returns: md5 of file
|
|
354
|
-
"""
|
|
355
|
-
return FSPath(path).md5(recalculate, followlinks)
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
def fs_copy(
|
|
359
|
-
src_path: PathLike,
|
|
360
|
-
dst_path: PathLike,
|
|
361
|
-
callback: Optional[Callable[[int], None]] = None,
|
|
362
|
-
followlinks: bool = False,
|
|
363
|
-
overwrite: bool = True,
|
|
364
|
-
):
|
|
365
|
-
"""File copy on file system
|
|
366
|
-
Copy content (excluding meta date) of file on `src_path` to `dst_path`.
|
|
367
|
-
`dst_path` must be a complete file name
|
|
368
|
-
|
|
369
|
-
.. note ::
|
|
370
|
-
|
|
371
|
-
The differences between this function and shutil.copyfile are:
|
|
372
|
-
|
|
373
|
-
1. If parent directory of dst_path doesn't exist, create it
|
|
374
|
-
|
|
375
|
-
2. Allow callback function, None by default.
|
|
376
|
-
callback: Optional[Callable[[int], None]], the int data is means
|
|
377
|
-
the size (in bytes) of the written data that is passed periodically
|
|
378
|
-
|
|
379
|
-
3. This function is thread-unsafe
|
|
380
|
-
|
|
381
|
-
:param src_path: Given path
|
|
382
|
-
:param dst_path: Target file path
|
|
383
|
-
:param callback: Called periodically during copy, and the input parameter is
|
|
384
|
-
the data size (in bytes) of copy since the last call
|
|
385
|
-
:param followlinks: False if regard symlink as file, else True
|
|
386
|
-
:param overwrite: whether or not overwrite file when exists, default is True
|
|
387
|
-
"""
|
|
388
|
-
return FSPath(src_path).copy(dst_path, callback, followlinks, overwrite)
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
def fs_sync(
|
|
392
|
-
src_path: PathLike,
|
|
393
|
-
dst_path: PathLike,
|
|
394
|
-
followlinks: bool = False,
|
|
395
|
-
force: bool = False,
|
|
396
|
-
overwrite: bool = True,
|
|
397
|
-
) -> None:
|
|
398
|
-
"""Force write of everything to disk.
|
|
399
|
-
|
|
400
|
-
:param src_path: Given path
|
|
401
|
-
:param dst_path: Target file path
|
|
402
|
-
:param followlinks: False if regard symlink as file, else True
|
|
403
|
-
:param force: Sync file forcible, do not ignore same files,
|
|
404
|
-
priority is higher than 'overwrite', default is False
|
|
405
|
-
:param overwrite: whether or not overwrite file when exists, default is True
|
|
406
|
-
"""
|
|
407
|
-
return FSPath(src_path).sync(dst_path, followlinks, force, overwrite)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
def fs_symlink(src_path: PathLike, dst_path: PathLike) -> None:
|
|
411
|
-
"""
|
|
412
|
-
Create a symbolic link pointing to src_path named dst_path.
|
|
413
|
-
|
|
414
|
-
:param src_path: Given path
|
|
415
|
-
:param dst_path: Destination path
|
|
416
|
-
"""
|
|
417
|
-
return FSPath(src_path).symlink(dst_path)
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
def fs_islink(path: PathLike) -> bool:
|
|
421
|
-
"""Test whether a path is a symbolic link
|
|
422
|
-
|
|
423
|
-
:param path: Given path
|
|
424
|
-
:return: If path is a symbolic link return True, else False
|
|
425
|
-
:rtype: bool
|
|
426
|
-
"""
|
|
427
|
-
return FSPath(path).is_symlink()
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
def fs_ismount(path: PathLike) -> bool:
|
|
431
|
-
"""Test whether a path is a mount point
|
|
432
|
-
|
|
433
|
-
:param path: Given path
|
|
434
|
-
:returns: True if a path is a mount point, else False
|
|
435
|
-
"""
|
|
436
|
-
return FSPath(path).is_mount()
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
def fs_save_as(file_object: BinaryIO, path: PathLike):
|
|
440
|
-
"""Write the opened binary stream to path
|
|
441
|
-
If parent directory of path doesn't exist, it will be created.
|
|
442
|
-
|
|
443
|
-
:param path: Given path
|
|
444
|
-
:param file_object: stream to be read
|
|
445
|
-
"""
|
|
446
|
-
return FSPath(path).save(file_object)
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
def fs_readlink(path) -> str:
|
|
450
|
-
"""
|
|
451
|
-
Return a string representing the path to which the symbolic link points.
|
|
452
|
-
:returns: Return a string representing the path to which the symbolic link points.
|
|
453
|
-
"""
|
|
454
|
-
return FSPath(path).readlink().path_without_protocol # pyre-ignore[7]
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
def fs_cwd() -> str:
|
|
458
|
-
"""Return current working directory
|
|
459
|
-
|
|
460
|
-
returns: Current working directory
|
|
461
|
-
"""
|
|
462
|
-
return os.getcwd()
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
def fs_home():
|
|
466
|
-
"""Return the home directory
|
|
467
|
-
|
|
468
|
-
returns: Home directory path
|
|
469
|
-
"""
|
|
470
|
-
return os.path.expanduser("~")
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
def fs_iglob(
|
|
474
|
-
path: PathLike, recursive: bool = True, missing_ok: bool = True
|
|
475
|
-
) -> Iterator[str]:
|
|
476
|
-
"""Return path iterator in ascending alphabetical order,
|
|
477
|
-
in which path matches glob pattern
|
|
478
|
-
|
|
479
|
-
1. If doesn't match any path, return empty list
|
|
480
|
-
Notice: ``glob.glob`` in standard library returns ['a/'] instead of empty list
|
|
481
|
-
when pathname is like `a/**`, recursive is True and directory 'a' doesn't exist.
|
|
482
|
-
fs_glob behaves like ``glob.glob`` in standard library under such circumstance.
|
|
483
|
-
2. No guarantee that each path in result is different, which means:
|
|
484
|
-
Assume there exists a path `/a/b/c/b/d.txt`
|
|
485
|
-
use path pattern like `/**/b/**/*.txt` to glob,
|
|
486
|
-
the path above will be returned twice
|
|
487
|
-
3. `**` will match any matched file, directory, symlink and '' by default,
|
|
488
|
-
when recursive is `True`
|
|
489
|
-
4. fs_glob returns same as glob.glob(pathname, recursive=True)
|
|
490
|
-
in ascending alphabetical order.
|
|
491
|
-
5. Hidden files (filename stars with '.') will not be found in the result
|
|
492
|
-
|
|
493
|
-
:param recursive: If False, `**` will not search directory recursively
|
|
494
|
-
:param missing_ok: If False and target path doesn't match any file,
|
|
495
|
-
raise FileNotFoundError
|
|
496
|
-
:returns: An iterator contains paths match `pathname`
|
|
497
|
-
"""
|
|
498
|
-
for path_obj in FSPath(path).iglob(
|
|
499
|
-
pattern="", recursive=recursive, missing_ok=missing_ok
|
|
500
|
-
):
|
|
501
|
-
yield path_obj.path_without_protocol # pyre-ignore[7]
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
def fs_glob(
|
|
505
|
-
path: PathLike, recursive: bool = True, missing_ok: bool = True
|
|
506
|
-
) -> List[str]:
|
|
507
|
-
"""Return path list in ascending alphabetical order,
|
|
508
|
-
in which path matches glob pattern
|
|
509
|
-
|
|
510
|
-
1. If doesn't match any path, return empty list
|
|
511
|
-
Notice: ``glob.glob`` in standard library returns ['a/'] instead of empty list
|
|
512
|
-
when pathname is like `a/**`, recursive is True and directory 'a' doesn't exist.
|
|
513
|
-
fs_glob behaves like ``glob.glob`` in standard library under such circumstance.
|
|
514
|
-
2. No guarantee that each path in result is different, which means:
|
|
515
|
-
Assume there exists a path `/a/b/c/b/d.txt`
|
|
516
|
-
use path pattern like `/**/b/**/*.txt` to glob,
|
|
517
|
-
the path above will be returned twice
|
|
518
|
-
3. `**` will match any matched file, directory, symlink and '' by default,
|
|
519
|
-
when recursive is `True`
|
|
520
|
-
4. fs_glob returns same as glob.glob(pathname, recursive=True)
|
|
521
|
-
in ascending alphabetical order.
|
|
522
|
-
5. Hidden files (filename stars with '.') will not be found in the result
|
|
523
|
-
|
|
524
|
-
:param recursive: If False, `**` will not search directory recursively
|
|
525
|
-
:param missing_ok: If False and target path doesn't match any file,
|
|
526
|
-
raise FileNotFoundError
|
|
527
|
-
:returns: A list contains paths match `pathname`
|
|
528
|
-
"""
|
|
529
|
-
return list(fs_iglob(path=path, recursive=recursive, missing_ok=missing_ok))
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
def fs_glob_stat(
|
|
533
|
-
path: PathLike, recursive: bool = True, missing_ok: bool = True
|
|
534
|
-
) -> Iterator[FileEntry]:
|
|
535
|
-
"""Return a list contains tuples of path and file stat,
|
|
536
|
-
in ascending alphabetical order, in which path matches glob pattern
|
|
537
|
-
|
|
538
|
-
1. If doesn't match any path, return empty list
|
|
539
|
-
Notice: ``glob.glob`` in standard library returns ['a/'] instead of empty list
|
|
540
|
-
when pathname is like `a/**`, recursive is True and directory 'a' doesn't exist.
|
|
541
|
-
fs_glob behaves like ``glob.glob`` in standard library under such circumstance.
|
|
542
|
-
2. No guarantee that each path in result is different, which means:
|
|
543
|
-
Assume there exists a path `/a/b/c/b/d.txt`
|
|
544
|
-
use path pattern like `/**/b/**/*.txt` to glob,
|
|
545
|
-
the path above will be returned twice.
|
|
546
|
-
3. `**` will match any matched file, directory, symlink and '' by default,
|
|
547
|
-
when recursive is `True`
|
|
548
|
-
4. fs_glob returns same as glob.glob(pathname, recursive=True)
|
|
549
|
-
in ascending alphabetical order.
|
|
550
|
-
5. Hidden files (filename stars with '.') will not be found in the result
|
|
551
|
-
|
|
552
|
-
:param recursive: If False, `**` will not search directory recursively
|
|
553
|
-
:param missing_ok: If False and target path doesn't match any file,
|
|
554
|
-
raise FileNotFoundError
|
|
555
|
-
:returns: A list contains tuples of path and file stat,
|
|
556
|
-
in which paths match `pathname`
|
|
557
|
-
"""
|
|
558
|
-
for path in fs_iglob(path=path, recursive=recursive, missing_ok=missing_ok):
|
|
559
|
-
yield FileEntry(os.path.basename(path), path, _make_stat(os.lstat(path)))
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
def fs_resolve(path: PathLike) -> str:
|
|
563
|
-
"""Equal to fs_realpath, return the real path of given path
|
|
564
|
-
|
|
565
|
-
:param path: Given path
|
|
566
|
-
:returns: Real path of given path
|
|
567
|
-
"""
|
|
568
|
-
return FSPath(path).realpath()
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
def fs_makedirs(path: PathLike, exist_ok: bool = False):
|
|
572
|
-
"""
|
|
573
|
-
make a directory on fs, including parent directory
|
|
574
|
-
|
|
575
|
-
If there exists a file on the path, raise FileExistsError
|
|
576
|
-
|
|
577
|
-
:param path: Given path
|
|
578
|
-
:param exist_ok: If False and target directory exists, raise FileExistsError
|
|
579
|
-
:raises: FileExistsError
|
|
580
|
-
"""
|
|
581
|
-
return FSPath(path).mkdir(parents=True, exist_ok=exist_ok)
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
def fs_lstat(path: PathLike) -> StatResult:
|
|
585
|
-
"""
|
|
586
|
-
Like Path.stat() but, if the path points to a symbolic link,
|
|
587
|
-
return the symbolic link’s information rather than its target’s.
|
|
588
|
-
|
|
589
|
-
:param path: Given path
|
|
590
|
-
:returns: StatResult
|
|
591
|
-
"""
|
|
592
|
-
return FSPath(path).lstat()
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
def fs_rename(src_path: PathLike, dst_path: PathLike, overwrite: bool = True) -> None:
|
|
596
|
-
"""
|
|
597
|
-
rename file on fs
|
|
598
|
-
|
|
599
|
-
:param src_path: Given path
|
|
600
|
-
:param dst_path: Given destination path
|
|
601
|
-
:param overwrite: whether or not overwrite file when exists
|
|
602
|
-
"""
|
|
603
|
-
FSPath(src_path).rename(dst_path, overwrite)
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
def fs_move(src_path: PathLike, dst_path: PathLike, overwrite: bool = True) -> None:
|
|
607
|
-
"""
|
|
608
|
-
rename file on fs
|
|
609
|
-
|
|
610
|
-
:param src_path: Given path
|
|
611
|
-
:param dst_path: Given destination path
|
|
612
|
-
:param overwrite: whether or not overwrite file when exists
|
|
613
|
-
"""
|
|
614
|
-
return fs_rename(src_path, dst_path, overwrite)
|