megfile 3.0.6.post1__py3-none-any.whl → 3.1.0.post1__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.
- docs/conf.py +67 -0
- megfile/cli.py +16 -16
- megfile/config.py +37 -6
- megfile/errors.py +26 -20
- megfile/fs.py +13 -8
- megfile/fs_path.py +69 -49
- megfile/hdfs.py +13 -8
- megfile/hdfs_path.py +49 -41
- megfile/http.py +1 -1
- megfile/http_path.py +35 -28
- megfile/interfaces.py +119 -48
- megfile/lib/base_prefetch_reader.py +9 -8
- megfile/lib/combine_reader.py +7 -7
- megfile/lib/fnmatch.py +2 -2
- megfile/lib/glob.py +3 -3
- megfile/lib/hdfs_prefetch_reader.py +2 -1
- megfile/lib/http_prefetch_reader.py +3 -2
- megfile/lib/lazy_handler.py +6 -5
- megfile/lib/s3_buffered_writer.py +8 -7
- megfile/lib/s3_cached_handler.py +3 -4
- megfile/lib/s3_limited_seekable_writer.py +5 -3
- megfile/lib/s3_memory_handler.py +10 -6
- megfile/lib/s3_pipe_handler.py +1 -1
- megfile/lib/s3_prefetch_reader.py +7 -5
- megfile/lib/s3_share_cache_reader.py +2 -2
- megfile/lib/shadow_handler.py +5 -5
- megfile/lib/stdio_handler.py +3 -3
- megfile/pathlike.py +156 -170
- megfile/s3.py +19 -13
- megfile/s3_path.py +98 -83
- megfile/sftp.py +25 -16
- megfile/sftp_path.py +109 -94
- megfile/smart.py +38 -28
- megfile/smart_path.py +6 -6
- megfile/stdio.py +3 -3
- megfile/stdio_path.py +5 -5
- megfile/utils/__init__.py +8 -27
- megfile/version.py +1 -1
- {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/METADATA +4 -5
- megfile-3.1.0.post1.dist-info/RECORD +55 -0
- {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/WHEEL +1 -1
- megfile-3.1.0.post1.dist-info/top_level.txt +7 -0
- scripts/convert_results_to_sarif.py +124 -0
- scripts/generate_file.py +268 -0
- megfile-3.0.6.post1.dist-info/RECORD +0 -52
- megfile-3.0.6.post1.dist-info/top_level.txt +0 -1
- {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/LICENSE +0 -0
- {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/LICENSE.pyre +0 -0
- {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/entry_points.txt +0 -0
megfile/smart.py
CHANGED
|
@@ -3,7 +3,7 @@ from collections import defaultdict
|
|
|
3
3
|
from functools import partial
|
|
4
4
|
from stat import S_ISDIR as stat_isdir
|
|
5
5
|
from stat import S_ISLNK as stat_islnk
|
|
6
|
-
from typing import IO, Any,
|
|
6
|
+
from typing import IO, Any, BinaryIO, Callable, Iterable, Iterator, List, Optional, Tuple
|
|
7
7
|
|
|
8
8
|
from tqdm import tqdm
|
|
9
9
|
|
|
@@ -74,7 +74,7 @@ def smart_symlink(src_path: PathLike, dst_path: PathLike) -> None:
|
|
|
74
74
|
Create a symbolic link pointing to src_path named path.
|
|
75
75
|
|
|
76
76
|
:param src_path: Source path
|
|
77
|
-
:param dst_path:
|
|
77
|
+
:param dst_path: Destination path
|
|
78
78
|
'''
|
|
79
79
|
return SmartPath(src_path).symlink(dst_path)
|
|
80
80
|
|
|
@@ -128,17 +128,17 @@ def smart_exists(path: PathLike, followlinks: bool = False) -> bool:
|
|
|
128
128
|
Test if path or s3_url exists
|
|
129
129
|
|
|
130
130
|
:param path: Path to be tested
|
|
131
|
-
:returns: True if path
|
|
131
|
+
:returns: True if path exists, else False
|
|
132
132
|
'''
|
|
133
133
|
return SmartPath(path).exists(followlinks=followlinks)
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
def smart_listdir(path: Optional[PathLike] = None) -> List[str]:
|
|
137
137
|
'''
|
|
138
|
-
Get all contents of given s3_url or file path. The result is in
|
|
138
|
+
Get all contents of given s3_url or file path. The result is in ascending alphabetical order.
|
|
139
139
|
|
|
140
140
|
:param path: Given path
|
|
141
|
-
:returns: All contents of given s3_url or file path in
|
|
141
|
+
:returns: All contents of given s3_url or file path in ascending alphabetical order.
|
|
142
142
|
:raises: FileNotFoundError, NotADirectoryError
|
|
143
143
|
'''
|
|
144
144
|
if path is None:
|
|
@@ -240,17 +240,17 @@ _copy_funcs = {
|
|
|
240
240
|
|
|
241
241
|
|
|
242
242
|
def register_copy_func(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
Callable[[str, str, Optional[Callable[[int], None]]], None]] = None,
|
|
243
|
+
src_protocol: str,
|
|
244
|
+
dst_protocol: str,
|
|
245
|
+
copy_func: Optional[Callable] = None,
|
|
247
246
|
) -> None:
|
|
248
247
|
'''
|
|
249
248
|
Used to register copy func between protocols, and do not allow duplicate registration
|
|
250
249
|
|
|
251
250
|
:param src_protocol: protocol name of source file, e.g. 's3'
|
|
252
251
|
:param dst_protocol: protocol name of destination file, e.g. 's3'
|
|
253
|
-
:param copy_func: copy func, its type is:
|
|
252
|
+
:param copy_func: copy func, its type is:
|
|
253
|
+
Callable[[str, str, Optional[Callable[[int], None]], Optional[bool], Optional[bool]], None]
|
|
254
254
|
'''
|
|
255
255
|
try:
|
|
256
256
|
_copy_funcs[src_protocol][dst_protocol]
|
|
@@ -343,7 +343,7 @@ def smart_copy(
|
|
|
343
343
|
dst_path,
|
|
344
344
|
callback=callback,
|
|
345
345
|
followlinks=followlinks,
|
|
346
|
-
overwrite=overwrite)
|
|
346
|
+
overwrite=overwrite)
|
|
347
347
|
except S3UnknownError as e:
|
|
348
348
|
if 'cannot schedule new futures after interpreter shutdown' in str(e):
|
|
349
349
|
_default_copy_func(
|
|
@@ -351,7 +351,7 @@ def smart_copy(
|
|
|
351
351
|
dst_path,
|
|
352
352
|
callback=callback,
|
|
353
353
|
followlinks=followlinks,
|
|
354
|
-
overwrite=overwrite)
|
|
354
|
+
overwrite=overwrite)
|
|
355
355
|
else:
|
|
356
356
|
raise
|
|
357
357
|
|
|
@@ -456,7 +456,7 @@ def smart_sync(
|
|
|
456
456
|
This parameter is in order to reduce file traversal times.
|
|
457
457
|
:param map_func: A Callable func like `map`. You can use ThreadPoolExecutor.map, Pool.map and so on if you need concurrent capability.
|
|
458
458
|
default is standard library `map`.
|
|
459
|
-
:param force: Sync file
|
|
459
|
+
:param force: Sync file forcible, do not ignore same files, priority is higher than 'overwrite', default is False
|
|
460
460
|
:param overwrite: whether or not overwrite file when exists, default is True
|
|
461
461
|
'''
|
|
462
462
|
if not smart_exists(src_path):
|
|
@@ -507,7 +507,7 @@ def smart_sync_with_progress(
|
|
|
507
507
|
This parameter is in order to reduce file traversal times.
|
|
508
508
|
:param map_func: A Callable func like `map`. You can use ThreadPoolExecutor.map, Pool.map and so on if you need concurrent capability.
|
|
509
509
|
default is standard library `map`.
|
|
510
|
-
:param force: Sync file
|
|
510
|
+
:param force: Sync file forcible, do not ignore same files, priority is higher than 'overwrite', default is False
|
|
511
511
|
:param overwrite: whether or not overwrite file when exists, default is True
|
|
512
512
|
'''
|
|
513
513
|
if not smart_exists(src_path):
|
|
@@ -620,7 +620,7 @@ def smart_open(
|
|
|
620
620
|
s3_open_func: Callable[[str, str], BinaryIO] = s3_open,
|
|
621
621
|
encoding: Optional[str] = None,
|
|
622
622
|
errors: Optional[str] = None,
|
|
623
|
-
**options) -> IO
|
|
623
|
+
**options) -> IO:
|
|
624
624
|
'''
|
|
625
625
|
Open a file on the path
|
|
626
626
|
|
|
@@ -680,8 +680,10 @@ def smart_path_join(path: PathLike, *other_paths: PathLike) -> str:
|
|
|
680
680
|
return fspath(SmartPath(path).joinpath(*other_paths))
|
|
681
681
|
|
|
682
682
|
|
|
683
|
-
def smart_walk(
|
|
684
|
-
|
|
683
|
+
def smart_walk(
|
|
684
|
+
path: PathLike,
|
|
685
|
+
followlinks: bool = False
|
|
686
|
+
) -> Iterator[Tuple[str, List[str], List[str]]]:
|
|
685
687
|
'''
|
|
686
688
|
Generate the file names in a directory tree by walking the tree top-down.
|
|
687
689
|
For each directory in the tree rooted at directory path (including path itself),
|
|
@@ -703,7 +705,8 @@ def smart_walk(path: PathLike, followlinks: bool = False
|
|
|
703
705
|
|
|
704
706
|
|
|
705
707
|
def smart_scan(
|
|
706
|
-
path: PathLike,
|
|
708
|
+
path: PathLike,
|
|
709
|
+
missing_ok: bool = True,
|
|
707
710
|
followlinks: bool = False) -> Iterator[str]:
|
|
708
711
|
'''
|
|
709
712
|
Iteratively traverse only files in given directory, in alphabetical order.
|
|
@@ -722,7 +725,8 @@ def smart_scan(
|
|
|
722
725
|
|
|
723
726
|
|
|
724
727
|
def smart_scan_stat(
|
|
725
|
-
path: PathLike,
|
|
728
|
+
path: PathLike,
|
|
729
|
+
missing_ok: bool = True,
|
|
726
730
|
followlinks: bool = False) -> Iterator[FileEntry]:
|
|
727
731
|
'''
|
|
728
732
|
Iteratively traverse only files in given directory, in alphabetical order.
|
|
@@ -737,13 +741,14 @@ def smart_scan_stat(
|
|
|
737
741
|
missing_ok=missing_ok, followlinks=followlinks)
|
|
738
742
|
|
|
739
743
|
|
|
740
|
-
def _group_glob(globstr:
|
|
744
|
+
def _group_glob(globstr: PathLike) -> List[str]:
|
|
741
745
|
'''
|
|
742
746
|
Split pathname, and group them by protocol, return the glob list of same group.
|
|
743
747
|
|
|
744
748
|
:param globstr: A glob string
|
|
745
749
|
:returns: A glob list after being grouped by protocol
|
|
746
750
|
'''
|
|
751
|
+
globstr = fspath(globstr)
|
|
747
752
|
glob_dict = defaultdict(list)
|
|
748
753
|
expanded_glob = ungloblize(globstr)
|
|
749
754
|
|
|
@@ -759,7 +764,8 @@ def _group_glob(globstr: str) -> List[str]:
|
|
|
759
764
|
|
|
760
765
|
|
|
761
766
|
def smart_glob(
|
|
762
|
-
pathname: PathLike,
|
|
767
|
+
pathname: PathLike,
|
|
768
|
+
recursive: bool = True,
|
|
763
769
|
missing_ok: bool = True) -> List[str]:
|
|
764
770
|
'''
|
|
765
771
|
Given pathname may contain shell wildcard characters, return path list in ascending alphabetical order, in which path matches glob pattern
|
|
@@ -781,7 +787,8 @@ def smart_glob(
|
|
|
781
787
|
|
|
782
788
|
|
|
783
789
|
def smart_iglob(
|
|
784
|
-
pathname: PathLike,
|
|
790
|
+
pathname: PathLike,
|
|
791
|
+
recursive: bool = True,
|
|
785
792
|
missing_ok: bool = True) -> Iterator[str]:
|
|
786
793
|
'''
|
|
787
794
|
Given pathname may contain shell wildcard characters, return path iterator in ascending alphabetical order, in which path matches glob pattern
|
|
@@ -801,7 +808,8 @@ def smart_iglob(
|
|
|
801
808
|
|
|
802
809
|
|
|
803
810
|
def smart_glob_stat(
|
|
804
|
-
pathname: PathLike,
|
|
811
|
+
pathname: PathLike,
|
|
812
|
+
recursive: bool = True,
|
|
805
813
|
missing_ok: bool = True) -> Iterator[FileEntry]:
|
|
806
814
|
'''
|
|
807
815
|
Given pathname may contain shell wildcard characters, return a list contains tuples of path and file stat in ascending alphabetical order, in which path matches glob pattern
|
|
@@ -839,7 +847,8 @@ def smart_load_from(path: PathLike) -> BinaryIO:
|
|
|
839
847
|
|
|
840
848
|
|
|
841
849
|
def smart_combine_open(
|
|
842
|
-
path_glob: str,
|
|
850
|
+
path_glob: str,
|
|
851
|
+
mode: str = 'rb',
|
|
843
852
|
open_func=smart_open) -> CombineReader:
|
|
844
853
|
'''Open a unified reader that supports multi file reading.
|
|
845
854
|
|
|
@@ -899,7 +908,8 @@ def smart_ismount(path: PathLike) -> bool:
|
|
|
899
908
|
|
|
900
909
|
|
|
901
910
|
def smart_load_content(
|
|
902
|
-
path: PathLike,
|
|
911
|
+
path: PathLike,
|
|
912
|
+
start: Optional[int] = None,
|
|
903
913
|
stop: Optional[int] = None) -> bytes:
|
|
904
914
|
'''
|
|
905
915
|
Get specified file from [start, stop) in bytes
|
|
@@ -918,7 +928,7 @@ def smart_load_content(
|
|
|
918
928
|
offset = -1
|
|
919
929
|
if start and stop:
|
|
920
930
|
offset = stop - start
|
|
921
|
-
return fd.read(offset)
|
|
931
|
+
return fd.read(offset) # pytype: disable=bad-return-type
|
|
922
932
|
|
|
923
933
|
|
|
924
934
|
def smart_save_content(path: PathLike, content: bytes) -> None:
|
|
@@ -937,7 +947,7 @@ def smart_load_text(path: PathLike) -> str:
|
|
|
937
947
|
param path: Path to be read
|
|
938
948
|
'''
|
|
939
949
|
with smart_open(path) as fd:
|
|
940
|
-
return fd.read()
|
|
950
|
+
return fd.read() # pytype: disable=bad-return-type
|
|
941
951
|
|
|
942
952
|
|
|
943
953
|
def smart_save_text(path: PathLike, text: str) -> None:
|
|
@@ -1038,4 +1048,4 @@ def smart_concat(src_paths: List[PathLike], dst_path: PathLike) -> None:
|
|
|
1038
1048
|
break
|
|
1039
1049
|
else:
|
|
1040
1050
|
concat_func = _concat_funcs.get(dst_protocol, _default_concat_func)
|
|
1041
|
-
concat_func(src_paths, dst_path)
|
|
1051
|
+
concat_func(src_paths, dst_path) # pyre-ignore[61]
|
megfile/smart_path.py
CHANGED
|
@@ -36,13 +36,13 @@ class SmartPath(BasePath):
|
|
|
36
36
|
if not isinstance(pathlike, BaseURIPath):
|
|
37
37
|
pathlike = self._create_pathlike(path)
|
|
38
38
|
if len(other_paths) > 0:
|
|
39
|
-
pathlike = pathlike.joinpath(*other_paths)
|
|
39
|
+
pathlike = pathlike.joinpath(*other_paths) # pyre-ignore[6]
|
|
40
40
|
self.path = str(pathlike)
|
|
41
41
|
self.pathlike = pathlike
|
|
42
42
|
|
|
43
43
|
@staticmethod
|
|
44
|
-
def _extract_protocol(
|
|
45
|
-
|
|
44
|
+
def _extract_protocol(
|
|
45
|
+
path: Union[PathLike, int]) -> Tuple[str, Union[str, int]]:
|
|
46
46
|
if isinstance(path, int):
|
|
47
47
|
protocol = "file"
|
|
48
48
|
path_without_protocol = path
|
|
@@ -64,7 +64,7 @@ class SmartPath(BasePath):
|
|
|
64
64
|
return protocol, path_without_protocol
|
|
65
65
|
|
|
66
66
|
@classmethod
|
|
67
|
-
def _create_pathlike(cls, path: Union[PathLike, int]) ->
|
|
67
|
+
def _create_pathlike(cls, path: Union[PathLike, int]) -> BaseURIPath:
|
|
68
68
|
protocol, _ = cls._extract_protocol(path)
|
|
69
69
|
if protocol.startswith('s3+'):
|
|
70
70
|
protocol = 's3'
|
|
@@ -122,7 +122,7 @@ class SmartPath(BasePath):
|
|
|
122
122
|
|
|
123
123
|
@property
|
|
124
124
|
def protocol(self) -> str:
|
|
125
|
-
return self.pathlike.protocol
|
|
125
|
+
return self.pathlike.protocol
|
|
126
126
|
|
|
127
127
|
@classmethod
|
|
128
128
|
def from_uri(cls, path: str):
|
|
@@ -185,5 +185,5 @@ class SmartPath(BasePath):
|
|
|
185
185
|
stem = _bind_property('stem')
|
|
186
186
|
|
|
187
187
|
|
|
188
|
-
def get_traditional_path(path: str
|
|
188
|
+
def get_traditional_path(path: PathLike) -> str:
|
|
189
189
|
return fspath(SmartPath(path).path)
|
megfile/stdio.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import IO,
|
|
1
|
+
from typing import IO, Optional
|
|
2
2
|
|
|
3
3
|
from megfile.interfaces import PathLike
|
|
4
4
|
from megfile.stdio_path import StdioPath, is_stdio
|
|
@@ -14,7 +14,7 @@ def stdio_open(
|
|
|
14
14
|
mode: str = 'rb',
|
|
15
15
|
encoding: Optional[str] = None,
|
|
16
16
|
errors: Optional[str] = None,
|
|
17
|
-
**kwargs) -> IO
|
|
17
|
+
**kwargs) -> IO:
|
|
18
18
|
'''Used to read or write stdio
|
|
19
19
|
|
|
20
20
|
.. note ::
|
|
@@ -25,4 +25,4 @@ def stdio_open(
|
|
|
25
25
|
:param mode: Only supports 'rb' and 'wb' now
|
|
26
26
|
:return: STDReader, STDWriter
|
|
27
27
|
'''
|
|
28
|
-
return StdioPath(path).open(mode, encoding, errors)
|
|
28
|
+
return StdioPath(path).open(mode, encoding, errors) # pyre-ignore[6]
|
megfile/stdio_path.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import io
|
|
2
|
-
from typing import IO,
|
|
2
|
+
from typing import IO, Optional, Union
|
|
3
3
|
|
|
4
4
|
from megfile.interfaces import BaseURIPath, PathLike
|
|
5
5
|
from megfile.lib.compat import fspath
|
|
@@ -77,7 +77,7 @@ class StdioPath(BaseURIPath):
|
|
|
77
77
|
mode: str = 'rb',
|
|
78
78
|
encoding: Optional[str] = None,
|
|
79
79
|
errors: Optional[str] = None,
|
|
80
|
-
**kwargs) -> IO
|
|
80
|
+
**kwargs) -> IO:
|
|
81
81
|
'''Used to read or write stdio
|
|
82
82
|
|
|
83
83
|
.. note ::
|
|
@@ -91,7 +91,7 @@ class StdioPath(BaseURIPath):
|
|
|
91
91
|
|
|
92
92
|
if 'b' not in mode:
|
|
93
93
|
fileobj = io.TextIOWrapper(
|
|
94
|
-
fileobj, encoding=encoding, errors=errors)
|
|
95
|
-
fileobj.mode = mode
|
|
94
|
+
fileobj, encoding=encoding, errors=errors)
|
|
95
|
+
fileobj.mode = mode # pyre-ignore[41]
|
|
96
96
|
|
|
97
|
-
return fileobj
|
|
97
|
+
return fileobj
|
megfile/utils/__init__.py
CHANGED
|
@@ -26,7 +26,7 @@ def get_content_size(fileobj: IO, *, intrusive: bool = False) -> int:
|
|
|
26
26
|
if isinstance(file, BufferedIOBase):
|
|
27
27
|
file = file.raw
|
|
28
28
|
if hasattr(file, '_content_size'):
|
|
29
|
-
return getattr(file, '_content_size')
|
|
29
|
+
return getattr(file, '_content_size') # pyre-ignore[16]
|
|
30
30
|
|
|
31
31
|
offset = fileobj.tell()
|
|
32
32
|
if not is_seekable(fileobj) and is_writable(fileobj):
|
|
@@ -69,13 +69,14 @@ def is_writable(fileobj: IO) -> bool:
|
|
|
69
69
|
return hasattr(fileobj, 'write')
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
def _is_pickle(fileobj
|
|
72
|
+
def _is_pickle(fileobj) -> bool:
|
|
73
73
|
''' Test if File Object is pickle'''
|
|
74
74
|
if fileobj.name.endswith('.pkl') or fileobj.name.endswith('.pickle'):
|
|
75
75
|
return True
|
|
76
76
|
|
|
77
77
|
if 'r' in fileobj.mode and 'b' in fileobj.mode:
|
|
78
78
|
offset = fileobj.tell()
|
|
79
|
+
fileobj.seek(0)
|
|
79
80
|
data = fileobj.read(2)
|
|
80
81
|
fileobj.seek(offset)
|
|
81
82
|
if len(data) >= 2 and data[0] == 128 and 2 <= data[1] <= 5:
|
|
@@ -114,7 +115,7 @@ def shadow_copy(fileobj: IO, intrusive: bool = True, buffered: bool = False):
|
|
|
114
115
|
from megfile.lib.shadow_handler import ShadowHandler
|
|
115
116
|
result = ShadowHandler(fileobj, intrusive=intrusive)
|
|
116
117
|
mode = get_mode(fileobj)
|
|
117
|
-
if "b" in mode and (buffered or _is_pickle(result)):
|
|
118
|
+
if "b" in mode and (buffered or _is_pickle(result)):
|
|
118
119
|
if "+" in mode:
|
|
119
120
|
result = BufferedRandom(result)
|
|
120
121
|
elif "x" in mode or "w" in mode or "a" in mode:
|
|
@@ -181,7 +182,7 @@ def binary_open(open_func):
|
|
|
181
182
|
fileobj = open_func(path, get_binary_mode(mode), **kwargs)
|
|
182
183
|
if 'b' not in mode:
|
|
183
184
|
fileobj = TextIOWrapper(fileobj, encoding=encoding, errors=errors)
|
|
184
|
-
fileobj.mode = mode
|
|
185
|
+
fileobj.mode = mode # pyre-ignore[41]
|
|
185
186
|
return fileobj
|
|
186
187
|
|
|
187
188
|
return wrapper
|
|
@@ -251,7 +252,7 @@ class classproperty(property):
|
|
|
251
252
|
return "value"
|
|
252
253
|
"""
|
|
253
254
|
|
|
254
|
-
def __get__(self, _, cls) -> object:
|
|
255
|
+
def __get__(self, _, cls) -> object:
|
|
255
256
|
"""
|
|
256
257
|
This method gets called when a property value is requested.
|
|
257
258
|
@param cls: The class type of the above instance.
|
|
@@ -260,7 +261,7 @@ class classproperty(property):
|
|
|
260
261
|
# apply the __get__ on the class
|
|
261
262
|
return super(classproperty, self).__get__(cls)
|
|
262
263
|
|
|
263
|
-
def __set__(self, cls_or_obj, value: object) -> None:
|
|
264
|
+
def __set__(self, cls_or_obj, value: object) -> None:
|
|
264
265
|
"""
|
|
265
266
|
This method gets called when a property value should be set.
|
|
266
267
|
@param cls_or_obj: The class or instance of which the property should be changed.
|
|
@@ -269,30 +270,10 @@ class classproperty(property):
|
|
|
269
270
|
# call this method only on the class, not the instance
|
|
270
271
|
super(classproperty, self).__set__(_get_class(cls_or_obj), value)
|
|
271
272
|
|
|
272
|
-
def __delete__(self, cls_or_obj) -> None:
|
|
273
|
+
def __delete__(self, cls_or_obj) -> None:
|
|
273
274
|
"""
|
|
274
275
|
This method gets called when a property should be deleted.
|
|
275
276
|
@param cls_or_obj: The class or instance of which the property should be deleted.
|
|
276
277
|
"""
|
|
277
278
|
# call this method only on the class, not the instance
|
|
278
279
|
super(classproperty, self).__delete__(_get_class(cls_or_obj))
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
class cachedproperty:
|
|
282
|
-
"""
|
|
283
|
-
A property that is only computed once per instance and then replaces itself
|
|
284
|
-
with an ordinary attribute. Deleting the attribute resets the property.
|
|
285
|
-
Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
|
|
286
|
-
""" # noqa
|
|
287
|
-
|
|
288
|
-
def __init__(self, func):
|
|
289
|
-
self.__name__ = func.__name__
|
|
290
|
-
self.__module__ = func.__module__
|
|
291
|
-
self.__doc__ = func.__doc__
|
|
292
|
-
self.__wrapped__ = func
|
|
293
|
-
|
|
294
|
-
def __get__(self, obj, cls):
|
|
295
|
-
if obj is None:
|
|
296
|
-
return self
|
|
297
|
-
value = obj.__dict__[self.__name__] = self.__wrapped__(obj)
|
|
298
|
-
return value
|
megfile/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = "3.0.
|
|
1
|
+
VERSION = "3.1.0.post1"
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: megfile
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.1.0.post1
|
|
4
4
|
Summary: Megvii file operation library
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Author-email: megvii <megfile@megvii.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/megvii-research/megfile
|
|
7
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
8
|
Classifier: Environment :: Console
|
|
10
9
|
Classifier: Intended Audience :: Developers
|
|
11
10
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
docs/conf.py,sha256=oypYf1FkqYtFfjhWlDtX3y2UCfplHqwm6kYloW2XuYM,2454
|
|
2
|
+
megfile/__init__.py,sha256=MT8SIXsmEUvtSpd1GHv6e3fFfR1gRnlEdkNNqv3gngo,6534
|
|
3
|
+
megfile/cli.py,sha256=PITdtme1mW6Dr0VRvMaeLy4t8AexAlpLVF5H6VVGTNk,22411
|
|
4
|
+
megfile/config.py,sha256=8rbkxa8kcbxHUMzvds3gdN9sxhyCvLsW9Sf4DfS9Ih4,2307
|
|
5
|
+
megfile/errors.py,sha256=w3f-B3-epz-d9sP8KmWn1ytdmD97q7wABsCOOuQe0no,13625
|
|
6
|
+
megfile/fs.py,sha256=Hij6xE273rU5YRxECT1hklVYZgaiuzK0wZcKHs9NDWE,11879
|
|
7
|
+
megfile/fs_path.py,sha256=A3WwSi34ddhyiPcT0sBIUMrliFPWF_4GHktPuS33GWg,40921
|
|
8
|
+
megfile/hdfs.py,sha256=824qbjkRcOS5uqDqOD54-kEC0P7CRHxSOFuVHsMquAw,9174
|
|
9
|
+
megfile/hdfs_path.py,sha256=SbZPAiSK55S3dkcrZDxHjA6F6_Nt8aCL_rXpVrm2Uuw,27085
|
|
10
|
+
megfile/http.py,sha256=ZN5U_otx7H-WqX4Fn04T0zAwxCqQq017u0-7j4cD5Sg,2021
|
|
11
|
+
megfile/http_path.py,sha256=mnoN5hHJro23cLny1r5ePMJ28r2gnBrzqA0S-grpwrE,16215
|
|
12
|
+
megfile/interfaces.py,sha256=PLNv0hDBTrTFJGTwT5mbDKYTsCjNryrHHMJCYhL9Wp0,8522
|
|
13
|
+
megfile/pathlike.py,sha256=FjY88X1IA4-ue5jcekwlIO740D0oT_wNo95y3eo6vNA,30685
|
|
14
|
+
megfile/s3.py,sha256=JfYWFHNJrBAoncB5RPDMyhjrIwVYGZ2lh8prGst-L_M,12874
|
|
15
|
+
megfile/s3_path.py,sha256=WvP6AsFpS0bR11ABbOYSMUOVm3H2ffYcKrBbXxZJdrI,93001
|
|
16
|
+
megfile/sftp.py,sha256=cXS1LZh4gtJgDCmR9p2_uM1wlycV34ebuTJGaceatVE,12984
|
|
17
|
+
megfile/sftp_path.py,sha256=QcV4DK192c5GL2CeK07JgpELpBXpGVAKswQ1JtZ2DZQ,53336
|
|
18
|
+
megfile/smart.py,sha256=3Rm-nI3HCLdljdo3mGn1JWFnw1qGwuxUunb1MIEJK0I,36032
|
|
19
|
+
megfile/smart_path.py,sha256=OMTM9JeowIa6j2Yn8XEH-HS4gWD3gBkKgSj8GBD08Bk,6734
|
|
20
|
+
megfile/stdio.py,sha256=rsBMGr4LaFYOQjL-6k4GE_WznLsa8cPzMhSVNEEDh5o,671
|
|
21
|
+
megfile/stdio_path.py,sha256=2n3gTEN1-7d8cCRsQJ7zj8rdP1VPlgr78oSClYndxXI,2806
|
|
22
|
+
megfile/version.py,sha256=HgxsH8zUeKbwsczoAuIOhPyGbI_oqu-LqLFys9BLbJQ,25
|
|
23
|
+
megfile/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
megfile/lib/base_prefetch_reader.py,sha256=iTHdWvpERMELgv2sEAsf9tiiJFDYp2mHzodszFrB9T4,13213
|
|
25
|
+
megfile/lib/combine_reader.py,sha256=dV1AblB8LTHK2a4aM03w1eBEcTpxMBWln9g_fuz0v7Y,4561
|
|
26
|
+
megfile/lib/compare.py,sha256=yG2fZve_gMg32rQVCdwixBdqgYRsjn-24TqhALQaOrA,2233
|
|
27
|
+
megfile/lib/compat.py,sha256=0wt3_atcYhSLCxUj_WuDlQa3E1atjZfwJQ12thiFh5Q,234
|
|
28
|
+
megfile/lib/fnmatch.py,sha256=qtlTdOoowgUvQuZNDrzvEl7hA4Sdtifa9eXd47LEJZY,4082
|
|
29
|
+
megfile/lib/glob.py,sha256=bqJ13xIBTbgS1mnqUZcI1Tga2M6TvJrWZP9vmFL2P0U,9724
|
|
30
|
+
megfile/lib/hdfs_prefetch_reader.py,sha256=ytp0td83M8NheMCBtQjrQpvGaBvConpRqgd8xSqdi-E,2092
|
|
31
|
+
megfile/lib/hdfs_tools.py,sha256=t4GeoBxO0HPahIQDrsK17WBsLZtcfAaNwWfappzZ5q8,442
|
|
32
|
+
megfile/lib/http_prefetch_reader.py,sha256=Owc_eaDGS752QnzatOnZ3zp19DuuftxWPS8kTXidi1A,4359
|
|
33
|
+
megfile/lib/joinpath.py,sha256=D4Px6-lnDDpYs1LMUHkTIGqMPJQ0oCBGfTzREs373iU,929
|
|
34
|
+
megfile/lib/lazy_handler.py,sha256=V_dQR2ac7LXJ6u__R5_VauvmxqQVdjydNIKwJjYUBeQ,1862
|
|
35
|
+
megfile/lib/s3_buffered_writer.py,sha256=i1cmUePalrhVXIzT_H-vS1mmhh4Bh_9QDrLJs8UwA1s,7060
|
|
36
|
+
megfile/lib/s3_cached_handler.py,sha256=7VmDgMjv9PlL_gBoCkEMJx2PQxUoo_dEPQLOTVNu1Bk,1396
|
|
37
|
+
megfile/lib/s3_limited_seekable_writer.py,sha256=_uDEtfWluurqULAtsWa6HbexKH3xcJG-ukhQUgfPryk,6239
|
|
38
|
+
megfile/lib/s3_memory_handler.py,sha256=HaQMzjtbhFHsjpymQ9lAXHQo7drSj7-q-Amo5Z2j_bw,4091
|
|
39
|
+
megfile/lib/s3_pipe_handler.py,sha256=BicJ0EyOwBDWIpvpSWk-ZWDrUAd2QZlTR3LVHl4_pPs,3571
|
|
40
|
+
megfile/lib/s3_prefetch_reader.py,sha256=ofzSn_MC6INAZY83oA3Dq1QNI0SS2b-NP6Ov8ajjLos,4283
|
|
41
|
+
megfile/lib/s3_share_cache_reader.py,sha256=AFwpyFQq4y-PXTnbFoXxLMQOJFIcJXUgVTrDMCuAMUg,3629
|
|
42
|
+
megfile/lib/shadow_handler.py,sha256=w0K2g31598DPonJORa-wTB5B34hKq2Zt7IIYDZsuhOY,2643
|
|
43
|
+
megfile/lib/stdio_handler.py,sha256=t2hxBE1vo25-kS6QQRMiDEG95rdMVx2z6wTnwuN6NUc,1968
|
|
44
|
+
megfile/lib/url.py,sha256=VbQLjo0s4AaV0iSk66BcjI68aUTcN9zBZ5x6-cM4Qvs,103
|
|
45
|
+
megfile/utils/__init__.py,sha256=QFDDhVAmptdMzYE91O6GRARHTalj_ZfSKZNF71uCj7w,8857
|
|
46
|
+
megfile/utils/mutex.py,sha256=-2KH3bNovKRd9zvsXq9n3bWM7rQdoG9hO7tUPxVG_Po,2538
|
|
47
|
+
scripts/convert_results_to_sarif.py,sha256=SI0vw4TrpJ9gAZ2pH8ywu-lXMYeZ-TYW2dLEHw5Rx84,4218
|
|
48
|
+
scripts/generate_file.py,sha256=OLAH9iZKQlHTjuV8zpC6exCXLS6bNdu4Njoc3IKO9Sc,10173
|
|
49
|
+
megfile-3.1.0.post1.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
50
|
+
megfile-3.1.0.post1.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
|
|
51
|
+
megfile-3.1.0.post1.dist-info/METADATA,sha256=0Q1RFftQQ8ewo_hz4GleF1x5ucyCzIPbMseirlbX6ls,9112
|
|
52
|
+
megfile-3.1.0.post1.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
|
|
53
|
+
megfile-3.1.0.post1.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
|
|
54
|
+
megfile-3.1.0.post1.dist-info/top_level.txt,sha256=oTnYXo1Z3V61qSWAKtnY9RkDgRSHvfRN38FQae6E0W0,50
|
|
55
|
+
megfile-3.1.0.post1.dist-info/RECORD,,
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the MIT license found in the
|
|
5
|
+
# LICENSE.pyre file in the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List
|
|
12
|
+
|
|
13
|
+
LOG: logging.Logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
Error = Dict[str, Any]
|
|
16
|
+
Location = Dict[str, Any]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _locations(errors: List[Error]) -> Dict[str, Location]:
|
|
20
|
+
locations = {
|
|
21
|
+
error["path"]: {
|
|
22
|
+
"uri": f"file://{Path.cwd() / error['path']}",
|
|
23
|
+
"index": 0,
|
|
24
|
+
} for error in errors
|
|
25
|
+
}
|
|
26
|
+
for index, location in enumerate(locations.values()):
|
|
27
|
+
location["index"] = index
|
|
28
|
+
return locations
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _to_sarif_result(error: Error, locations: Dict[str,
|
|
32
|
+
Location]) -> Dict[str, Any]:
|
|
33
|
+
LOG.info(f"Transforming:\n{error}")
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
"ruleId":
|
|
37
|
+
"type-error",
|
|
38
|
+
"ruleIndex":
|
|
39
|
+
0,
|
|
40
|
+
"level":
|
|
41
|
+
"error",
|
|
42
|
+
"message": {
|
|
43
|
+
"text": error["description"],
|
|
44
|
+
},
|
|
45
|
+
"locations":
|
|
46
|
+
[
|
|
47
|
+
{
|
|
48
|
+
"physicalLocation":
|
|
49
|
+
{
|
|
50
|
+
"artifactLocation": locations[error["path"]],
|
|
51
|
+
"region":
|
|
52
|
+
{
|
|
53
|
+
"startLine": error["line"],
|
|
54
|
+
"startColumn": error["column"] + 1,
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _to_sarif(errors: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
63
|
+
LOG.info(f"Transforming:\n{errors}")
|
|
64
|
+
locations = _locations(errors)
|
|
65
|
+
return {
|
|
66
|
+
"version":
|
|
67
|
+
"2.1.0",
|
|
68
|
+
"$schema":
|
|
69
|
+
"http://json.schemastore.org/sarif-2.1.0-rtm.4",
|
|
70
|
+
"runs":
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
"tool":
|
|
74
|
+
{
|
|
75
|
+
"driver":
|
|
76
|
+
{
|
|
77
|
+
"name":
|
|
78
|
+
"Pyre",
|
|
79
|
+
"informationUri":
|
|
80
|
+
"https://www.pyre-check.org",
|
|
81
|
+
"rules":
|
|
82
|
+
[
|
|
83
|
+
{
|
|
84
|
+
"id":
|
|
85
|
+
"type-error",
|
|
86
|
+
"shortDescription":
|
|
87
|
+
{
|
|
88
|
+
"text": "Type Error"
|
|
89
|
+
},
|
|
90
|
+
"helpUri":
|
|
91
|
+
"https://www.pyre-check.org",
|
|
92
|
+
"help":
|
|
93
|
+
{
|
|
94
|
+
"text":
|
|
95
|
+
"Pyre is a type checker for Python"
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"artifacts":
|
|
102
|
+
[
|
|
103
|
+
{
|
|
104
|
+
"location": location
|
|
105
|
+
} for location in sorted(
|
|
106
|
+
locations.values(),
|
|
107
|
+
key=lambda location: location["index"])
|
|
108
|
+
],
|
|
109
|
+
"results":
|
|
110
|
+
[
|
|
111
|
+
_to_sarif_result(error, locations)
|
|
112
|
+
for error in errors
|
|
113
|
+
],
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
if __name__ == "__main__":
|
|
120
|
+
logging.basicConfig(
|
|
121
|
+
format="%(asctime)s [%(levelname)s] %(message)s", level=logging.DEBUG)
|
|
122
|
+
|
|
123
|
+
sarif = _to_sarif(json.load(sys.stdin))
|
|
124
|
+
json.dump(sarif, sys.stdout, indent=4)
|