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.
Files changed (49) hide show
  1. docs/conf.py +67 -0
  2. megfile/cli.py +16 -16
  3. megfile/config.py +37 -6
  4. megfile/errors.py +26 -20
  5. megfile/fs.py +13 -8
  6. megfile/fs_path.py +69 -49
  7. megfile/hdfs.py +13 -8
  8. megfile/hdfs_path.py +49 -41
  9. megfile/http.py +1 -1
  10. megfile/http_path.py +35 -28
  11. megfile/interfaces.py +119 -48
  12. megfile/lib/base_prefetch_reader.py +9 -8
  13. megfile/lib/combine_reader.py +7 -7
  14. megfile/lib/fnmatch.py +2 -2
  15. megfile/lib/glob.py +3 -3
  16. megfile/lib/hdfs_prefetch_reader.py +2 -1
  17. megfile/lib/http_prefetch_reader.py +3 -2
  18. megfile/lib/lazy_handler.py +6 -5
  19. megfile/lib/s3_buffered_writer.py +8 -7
  20. megfile/lib/s3_cached_handler.py +3 -4
  21. megfile/lib/s3_limited_seekable_writer.py +5 -3
  22. megfile/lib/s3_memory_handler.py +10 -6
  23. megfile/lib/s3_pipe_handler.py +1 -1
  24. megfile/lib/s3_prefetch_reader.py +7 -5
  25. megfile/lib/s3_share_cache_reader.py +2 -2
  26. megfile/lib/shadow_handler.py +5 -5
  27. megfile/lib/stdio_handler.py +3 -3
  28. megfile/pathlike.py +156 -170
  29. megfile/s3.py +19 -13
  30. megfile/s3_path.py +98 -83
  31. megfile/sftp.py +25 -16
  32. megfile/sftp_path.py +109 -94
  33. megfile/smart.py +38 -28
  34. megfile/smart_path.py +6 -6
  35. megfile/stdio.py +3 -3
  36. megfile/stdio_path.py +5 -5
  37. megfile/utils/__init__.py +8 -27
  38. megfile/version.py +1 -1
  39. {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/METADATA +4 -5
  40. megfile-3.1.0.post1.dist-info/RECORD +55 -0
  41. {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/WHEEL +1 -1
  42. megfile-3.1.0.post1.dist-info/top_level.txt +7 -0
  43. scripts/convert_results_to_sarif.py +124 -0
  44. scripts/generate_file.py +268 -0
  45. megfile-3.0.6.post1.dist-info/RECORD +0 -52
  46. megfile-3.0.6.post1.dist-info/top_level.txt +0 -1
  47. {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/LICENSE +0 -0
  48. {megfile-3.0.6.post1.dist-info → megfile-3.1.0.post1.dist-info}/LICENSE.pyre +0 -0
  49. {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, AnyStr, BinaryIO, Callable, Iterable, Iterator, List, Optional, Tuple
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: Desination 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 eixsts, else False
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 acsending alphabetical order.
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 acsending alphabetical order.
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
- src_protocol: str,
244
- dst_protocol: str,
245
- copy_func: Optional[
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: Callable[[str, str, Optional[Callable[[int], None]]], None]
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) # type: ignore
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) # type: ignore
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 forcely, do not ignore same files, priority is higher than 'overwrite', default is False
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 forcely, do not ignore same files, priority is higher than 'overwrite', default is False
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[AnyStr]: # pytype: disable=signature-mismatch
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(path: PathLike, followlinks: bool = False
684
- ) -> Iterator[Tuple[str, List[str], List[str]]]:
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, missing_ok: bool = True,
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, missing_ok: bool = True,
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: str) -> List[str]:
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, recursive: bool = True,
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, recursive: bool = True,
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, recursive: bool = True,
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, mode: str = 'rb',
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, start: Optional[int] = None,
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(path: Union[PathLike, int]
45
- ) -> Tuple[str, Union[str, int]]:
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]) -> BasePath:
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 # pytype: disable=attribute-error
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, AnyStr, Optional
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[AnyStr]: # pytype: disable=signature-mismatch
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, AnyStr, Optional, Union
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[AnyStr]: # pytype: disable=signature-mismatch
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) # type: ignore
95
- fileobj.mode = mode
94
+ fileobj, encoding=encoding, errors=errors)
95
+ fileobj.mode = mode # pyre-ignore[41]
96
96
 
97
- return fileobj # type: ignore
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: IO) -> bool:
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)): # pytype: disable=wrong-arg-types
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: # type: ignore
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: # type: ignore
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: # type: ignore
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.6.post1"
1
+ VERSION = "3.1.0.post1"
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: megfile
3
- Version: 3.0.6.post1
3
+ Version: 3.1.0.post1
4
4
  Summary: Megvii file operation library
5
- Home-page: https://github.com/megvii-research/megfile
6
- Author: megvii
7
- Author-email: megfile@megvii.com
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: setuptools (70.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,7 @@
1
+ dist
2
+ docs
3
+ empty
4
+ html_cov
5
+ html_doc
6
+ megfile
7
+ scripts
@@ -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)