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/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)