megfile 3.1.5__py3-none-any.whl → 3.1.6.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.
megfile/cli.py CHANGED
@@ -29,6 +29,7 @@ from megfile.smart import (
29
29
  smart_open,
30
30
  smart_path_join,
31
31
  smart_readlink,
32
+ smart_relpath,
32
33
  smart_remove,
33
34
  smart_rename,
34
35
  smart_scan_stat,
@@ -78,7 +79,7 @@ def get_echo_path(file_stat, base_path: str = "", full_path: bool = False):
78
79
  elif full_path:
79
80
  path = file_stat.path
80
81
  else:
81
- path = os.path.relpath(file_stat.path, start=base_path)
82
+ path = smart_relpath(file_stat.path, start=base_path)
82
83
  return path
83
84
 
84
85
 
megfile/config.py CHANGED
@@ -60,3 +60,5 @@ HDFS_MAX_RETRY_TIMES = int(
60
60
  SFTP_MAX_RETRY_TIMES = int(
61
61
  os.getenv("MEGFILE_SFTP_MAX_RETRY_TIMES") or DEFAULT_MAX_RETRY_TIMES
62
62
  )
63
+
64
+ HTTP_AUTH_HEADERS = ("Authorization", "Www-Authenticate", "Cookie", "Cookie2")
megfile/errors.py CHANGED
@@ -366,7 +366,7 @@ def translate_s3_error(s3_error: Exception, s3_url: PathLike) -> Exception:
366
366
  "Invalid configuration: %r, code: %r, message: %r, endpoint: %r"
367
367
  % (s3_url, code, message, s3_endpoint_url(s3_url))
368
368
  )
369
- if code in ("InvalidRange"):
369
+ if code in ("InvalidRange", "Requested Range Not Satisfiable"):
370
370
  return S3InvalidRangeError(
371
371
  "Index out of range: %r, code: %r, message: %r, endpoint: %r"
372
372
  % (
@@ -76,7 +76,11 @@ class S3PrefetchReader(BasePrefetchReader):
76
76
  try:
77
77
  start, end = 0, self._block_size - 1
78
78
  first_index_response = self._fetch_response(start=start, end=end)
79
- content_size = int(first_index_response["ContentRange"].split("/")[-1])
79
+ if "ContentRange" in first_index_response:
80
+ content_size = int(first_index_response["ContentRange"].split("/")[-1])
81
+ else:
82
+ # usually when read a file only have one block
83
+ content_size = int(first_index_response["ContentLength"])
80
84
  except S3InvalidRangeError:
81
85
  # usually when read a empty file
82
86
  # can use minio test empty file: https://hub.docker.com/r/minio/minio
megfile/pathlike.py CHANGED
@@ -636,8 +636,8 @@ class URIPath(BaseURIPath):
636
636
  relative = path[len(other_path) :]
637
637
  relative = relative.lstrip("/")
638
638
  return type(self)(relative) # pyre-ignore[19]
639
- else:
640
- raise ValueError("%r does not start with %r" % (path, other))
639
+
640
+ raise ValueError("%r does not start with %r" % (path, other))
641
641
 
642
642
  def with_name(self: Self, name: str) -> Self:
643
643
  """Return a new path with the name changed"""
@@ -655,6 +655,21 @@ class URIPath(BaseURIPath):
655
655
  raw_suffix = self.suffix
656
656
  return self.from_path(path[: len(path) - len(raw_suffix)] + suffix)
657
657
 
658
+ def relpath(self, start=None):
659
+ """Return the relative path."""
660
+ if start is None:
661
+ raise TypeError("start is required")
662
+
663
+ other_path = self.from_path(start).path_with_protocol
664
+ path = self.path_with_protocol
665
+
666
+ if path.startswith(other_path):
667
+ relative = path[len(other_path) :]
668
+ relative = relative.lstrip("/")
669
+ return relative
670
+
671
+ raise ValueError("%r does not start with %r" % (path, other_path))
672
+
658
673
  def is_absolute(self) -> bool:
659
674
  return True
660
675
 
megfile/s3_path.py CHANGED
@@ -7,16 +7,18 @@ from concurrent.futures import ThreadPoolExecutor
7
7
  from functools import cached_property, lru_cache, wraps
8
8
  from logging import getLogger as get_logger
9
9
  from typing import IO, Any, BinaryIO, Callable, Dict, Iterator, List, Optional, Tuple
10
+ from urllib.parse import urlparse
10
11
 
11
12
  import boto3
12
13
  import botocore
13
- from botocore.awsrequest import AWSResponse
14
+ from botocore.awsrequest import AWSPreparedRequest, AWSResponse
14
15
 
15
16
  from megfile.config import (
16
17
  DEFAULT_BLOCK_SIZE,
17
18
  DEFAULT_MAX_BLOCK_SIZE,
18
19
  DEFAULT_MIN_BLOCK_SIZE,
19
20
  GLOBAL_MAX_WORKERS,
21
+ HTTP_AUTH_HEADERS,
20
22
  S3_CLIENT_CACHE_MODE,
21
23
  S3_MAX_RETRY_TIMES,
22
24
  )
@@ -76,6 +78,7 @@ from megfile.utils import (
76
78
  generate_cache_path,
77
79
  get_binary_mode,
78
80
  get_content_offset,
81
+ is_domain_or_subdomain,
79
82
  is_readable,
80
83
  necessary_params,
81
84
  process_local,
@@ -122,7 +125,7 @@ max_retries = S3_MAX_RETRY_TIMES
122
125
  max_keys = 1000
123
126
 
124
127
 
125
- def _patch_make_request(client: botocore.client.BaseClient):
128
+ def _patch_make_request(client: botocore.client.BaseClient, redirect: bool = False):
126
129
  def after_callback(result: Tuple[AWSResponse, dict], *args, **kwargs):
127
130
  if (
128
131
  not isinstance(result, tuple)
@@ -161,6 +164,32 @@ def _patch_make_request(client: botocore.client.BaseClient):
161
164
  before_callback=before_callback,
162
165
  retry_callback=retry_callback,
163
166
  )
167
+
168
+ def patch_send(send):
169
+ def patched_send(request: AWSPreparedRequest) -> AWSResponse:
170
+ response: AWSResponse = send(request)
171
+ if (
172
+ request.method == "GET" # only support GET method for now
173
+ and response.status_code in (301, 302, 307, 308)
174
+ and "Location" in response.headers
175
+ ):
176
+ # Permit sending auth/cookie headers from "foo.com" to "sub.foo.com".
177
+ # See also: https://go.dev/src/net/http/client.go#L980
178
+ location = response.headers["Location"]
179
+ ihost = urlparse(request.url).hostname
180
+ dhost = urlparse(location).hostname
181
+ if not is_domain_or_subdomain(dhost, ihost):
182
+ for name in HTTP_AUTH_HEADERS:
183
+ request.headers.pop(name, None)
184
+ request.url = location
185
+ response = send(request)
186
+ return response
187
+
188
+ return patched_send
189
+
190
+ if redirect:
191
+ client._endpoint._send = patch_send(client._endpoint._send)
192
+
164
193
  return client
165
194
 
166
195
 
@@ -180,7 +209,11 @@ def parse_s3_url(s3_url: PathLike) -> Tuple[str, str]:
180
209
 
181
210
 
182
211
  def get_scoped_config(profile_name: Optional[str] = None) -> Dict:
183
- return get_s3_session(profile_name=profile_name)._session.get_scoped_config()
212
+ try:
213
+ session = get_s3_session(profile_name=profile_name)
214
+ except botocore.exceptions.ProfileNotFound:
215
+ session = get_s3_session()
216
+ return session._session.get_scoped_config()
184
217
 
185
218
 
186
219
  @lru_cache()
@@ -224,25 +257,22 @@ def get_s3_session(profile_name=None) -> boto3.Session:
224
257
  )
225
258
 
226
259
 
260
+ def get_env_var(env_name: str, profile_name=None):
261
+ if profile_name:
262
+ return os.getenv(f"{profile_name}__{env_name}".upper())
263
+ return os.getenv(env_name.upper())
264
+
265
+
266
+ def parse_boolean(value: Optional[str], default: bool = False) -> bool:
267
+ if value is None:
268
+ return default
269
+ return value.lower() in ("true", "yes", "1")
270
+
271
+
227
272
  def get_access_token(profile_name=None):
228
- access_key_env_name = (
229
- f"{profile_name}__AWS_ACCESS_KEY_ID".upper()
230
- if profile_name
231
- else "AWS_ACCESS_KEY_ID"
232
- )
233
- secret_key_env_name = (
234
- f"{profile_name}__AWS_SECRET_ACCESS_KEY".upper()
235
- if profile_name
236
- else "AWS_SECRET_ACCESS_KEY"
237
- )
238
- session_token_env_name = (
239
- f"{profile_name}__AWS_SESSION_TOKEN".upper()
240
- if profile_name
241
- else "AWS_SESSION_TOKEN"
242
- )
243
- access_key = os.getenv(access_key_env_name)
244
- secret_key = os.getenv(secret_key_env_name)
245
- session_token = os.getenv(session_token_env_name)
273
+ access_key = get_env_var("AWS_ACCESS_KEY_ID", profile_name=profile_name)
274
+ secret_key = get_env_var("AWS_SECRET_ACCESS_KEY", profile_name=profile_name)
275
+ session_token = get_env_var("AWS_SESSION_TOKEN", profile_name=profile_name)
246
276
  if access_key and secret_key:
247
277
  return access_key, secret_key, session_token
248
278
 
@@ -289,10 +319,7 @@ def get_s3_client(
289
319
  connect_timeout=5, max_pool_connections=GLOBAL_MAX_WORKERS
290
320
  )
291
321
 
292
- addressing_style_env_key = "AWS_S3_ADDRESSING_STYLE"
293
- if profile_name:
294
- addressing_style_env_key = f"{profile_name}__AWS_S3_ADDRESSING_STYLE".upper()
295
- addressing_style = os.environ.get(addressing_style_env_key)
322
+ addressing_style = get_env_var("AWS_S3_ADDRESSING_STYLE", profile_name=profile_name)
296
323
  if addressing_style:
297
324
  config = config.merge(
298
325
  botocore.config.Config(s3={"addressing_style": addressing_style})
@@ -303,15 +330,25 @@ def get_s3_client(
303
330
  session = get_s3_session(profile_name=profile_name)
304
331
  except botocore.exceptions.ProfileNotFound:
305
332
  session = get_s3_session()
333
+
334
+ s3_config = get_scoped_config(profile_name=profile_name).get("s3", {})
335
+ verify = get_env_var("AWS_S3_VERIFY", profile_name=profile_name)
336
+ verify = verify or s3_config.get("verify")
337
+ verify = parse_boolean(verify, default=True)
338
+ redirect = get_env_var("AWS_S3_REDIRECT", profile_name=profile_name)
339
+ redirect = redirect or s3_config.get("redirect")
340
+ redirect = parse_boolean(redirect, default=False)
341
+
306
342
  client = session.client(
307
343
  "s3",
308
344
  endpoint_url=get_endpoint_url(profile_name=profile_name),
345
+ verify=verify,
309
346
  config=config,
310
347
  aws_access_key_id=access_key,
311
348
  aws_secret_access_key=secret_key,
312
349
  aws_session_token=session_token,
313
350
  )
314
- client = _patch_make_request(client)
351
+ client = _patch_make_request(client, redirect=redirect)
315
352
  return client
316
353
 
317
354
 
megfile/smart_path.py CHANGED
@@ -1,11 +1,11 @@
1
1
  import os
2
2
  from configparser import ConfigParser
3
3
  from pathlib import PurePath
4
- from typing import Dict, Tuple, Union
4
+ from typing import Dict, Optional, Tuple, Union
5
5
 
6
6
  from megfile.lib.compat import fspath
7
7
  from megfile.lib.url import get_url_scheme
8
- from megfile.utils import classproperty
8
+ from megfile.utils import cached_classproperty
9
9
 
10
10
  from .errors import ProtocolExistsError, ProtocolNotFoundError
11
11
  from .interfaces import BasePath, BaseURIPath, PathLike
@@ -54,15 +54,15 @@ class SmartPath(BasePath):
54
54
  self.path = str(pathlike)
55
55
  self.pathlike = pathlike
56
56
 
57
- @classproperty
57
+ @cached_classproperty
58
58
  def _aliases(cls) -> Dict[str, Dict[str, str]]:
59
59
  config_path = os.path.expanduser(aliases_config)
60
- aliases = _load_aliases_config(config_path)
61
- setattr(cls, "_aliases", aliases)
62
- return aliases
60
+ return _load_aliases_config(config_path)
63
61
 
64
- @staticmethod
65
- def _extract_protocol(path: Union[PathLike, int]) -> Tuple[str, Union[str, int]]:
62
+ @classmethod
63
+ def _extract_protocol(
64
+ cls, path: Union[PathLike, int]
65
+ ) -> Tuple[str, Union[str, int]]:
66
66
  if isinstance(path, int):
67
67
  protocol = "file"
68
68
  path_without_protocol = path
@@ -74,27 +74,26 @@ class SmartPath(BasePath):
74
74
  else:
75
75
  path_without_protocol = path[len(protocol) + 3 :]
76
76
  elif isinstance(path, (BaseURIPath, SmartPath)):
77
- protocol = path.protocol
78
- path_without_protocol = str(path)
77
+ return str(path.protocol), str(path)
79
78
  elif isinstance(path, (PurePath, BasePath)):
80
- protocol, path_without_protocol = SmartPath._extract_protocol(fspath(path))
79
+ return SmartPath._extract_protocol(fspath(path))
81
80
  else:
82
81
  raise ProtocolNotFoundError("protocol not found: %r" % path)
83
- return protocol, path_without_protocol
84
-
85
- @classmethod
86
- def _create_pathlike(cls, path: Union[PathLike, int]) -> BaseURIPath:
87
- protocol, path_without_protocol = cls._extract_protocol(path)
88
82
  aliases: Dict[str, Dict[str, str]] = cls._aliases # pyre-ignore[9]
89
83
  if protocol in aliases:
90
84
  protocol = aliases[protocol]["protocol"]
91
- path = protocol + "://" + str(path_without_protocol)
85
+ path = "%s://%s" % (protocol, path_without_protocol)
86
+ return protocol, path
87
+
88
+ @classmethod
89
+ def _create_pathlike(cls, path: Union[PathLike, int]) -> BaseURIPath:
90
+ protocol, unaliased_path = cls._extract_protocol(path)
92
91
  if protocol.startswith("s3+"):
93
92
  protocol = "s3"
94
93
  if protocol not in cls._registered_protocols:
95
94
  raise ProtocolNotFoundError("protocol %r not found: %r" % (protocol, path))
96
95
  path_class = cls._registered_protocols[protocol]
97
- return path_class(path)
96
+ return path_class(unaliased_path)
98
97
 
99
98
  @classmethod
100
99
  def register(cls, path_class, override_ok: bool = False):
@@ -137,7 +136,6 @@ class SmartPath(BasePath):
137
136
  joinpath = _bind_function("joinpath")
138
137
  abspath = _bind_function("abspath")
139
138
  realpath = _bind_function("realpath")
140
- relpath = _bind_function("relpath")
141
139
  is_absolute = _bind_function("is_absolute")
142
140
  is_mount = _bind_function("is_mount")
143
141
  md5 = _bind_function("md5")
@@ -150,6 +148,16 @@ class SmartPath(BasePath):
150
148
  def from_uri(cls, path: str):
151
149
  return cls(path)
152
150
 
151
+ def relpath(self, start: Optional[str] = None) -> str:
152
+ """Return the relative path of given path
153
+
154
+ :param start: Given start directory
155
+ :returns: Relative path from start
156
+ """
157
+ if start is not None:
158
+ _, start = SmartPath._extract_protocol(fspath(start))
159
+ return self.pathlike.relpath(start=start)
160
+
153
161
  as_uri = _bind_function("as_uri")
154
162
  as_posix = _bind_function("as_posix")
155
163
  __lt__ = _bind_function("__lt__")
@@ -170,7 +178,6 @@ class SmartPath(BasePath):
170
178
  is_mount = _bind_function("is_mount")
171
179
  abspath = _bind_function("abspath")
172
180
  realpath = _bind_function("realpath")
173
- relpath = _bind_function("relpath")
174
181
  iterdir = _bind_function("iterdir")
175
182
  cwd = _bind_function("cwd")
176
183
  home = _bind_function("home")
megfile/utils/__init__.py CHANGED
@@ -4,7 +4,7 @@ import math
4
4
  import os
5
5
  import uuid
6
6
  from copy import copy
7
- from functools import wraps
7
+ from functools import cached_property, wraps
8
8
  from io import (
9
9
  BufferedIOBase,
10
10
  BufferedRandom,
@@ -15,6 +15,7 @@ from io import (
15
15
  TextIOBase,
16
16
  TextIOWrapper,
17
17
  )
18
+ from threading import RLock
18
19
  from typing import IO, Callable, Optional
19
20
 
20
21
  from megfile.utils.mutex import ProcessLocal, ThreadLocal
@@ -298,3 +299,58 @@ class classproperty(property):
298
299
  """
299
300
  # call this method only on the class, not the instance
300
301
  super(classproperty, self).__delete__(_get_class(cls_or_obj))
302
+
303
+
304
+ class cached_classproperty(cached_property):
305
+ """
306
+ The use this class as a decorator for your class property with cache.
307
+ Example:
308
+ @cached_classproperty
309
+ def prop(cls):
310
+ return "value"
311
+ """
312
+
313
+ def __init__(self, func: Callable) -> None:
314
+ """
315
+ This method initializes the cached_classproperty instance.
316
+ @param func: The function to be called when the property value is requested.
317
+ """
318
+ super().__init__(func)
319
+ # Python 3.12 removed the lock attribute from cached_property.
320
+ # Maybe we should remove this in the future.
321
+ # See also: https://github.com/python/cpython/pull/101890
322
+ # https://github.com/python/cpython/issues/87634
323
+ if not hasattr(func, "lock"):
324
+ self.lock = RLock()
325
+
326
+ def __get__( # pyre-ignore[14]
327
+ self,
328
+ _,
329
+ cls, # pytype: disable=signature-mismatch
330
+ ) -> object:
331
+ """
332
+ This method gets called when a property value is requested.
333
+ @param cls: The class type of the above instance.
334
+ @return: The value of the property.
335
+ """
336
+ if self.attrname is None:
337
+ raise TypeError(
338
+ "Cannot use cached_classproperty instance without calling "
339
+ "__set_name__ on it."
340
+ )
341
+ with self.lock:
342
+ # check if another thread filled cache while we awaited lock
343
+ # cannot use getattr since it will cause RecursionError
344
+ val = cls.__dict__[self.attrname]
345
+ if val is self:
346
+ val = self.func(cls)
347
+ setattr(cls, self.attrname, val)
348
+ return val
349
+
350
+
351
+ def is_domain_or_subdomain(sub, parent):
352
+ if sub == parent:
353
+ return True
354
+ if sub.endswith(f".{parent}"):
355
+ return True
356
+ return False
megfile/version.py CHANGED
@@ -1 +1 @@
1
- VERSION = "3.1.5"
1
+ VERSION = "3.1.6.post1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: megfile
3
- Version: 3.1.5
3
+ Version: 3.1.6.post1
4
4
  Summary: Megvii file operation library
5
5
  Author-email: megvii <megfile@megvii.com>
6
6
  Project-URL: Homepage, https://github.com/megvii-research/megfile
@@ -1,8 +1,8 @@
1
1
  docs/conf.py,sha256=sfDSly5jO8W_RmuAptOIp4hd8dNcO-9a5XrHTbxFnNo,2448
2
2
  megfile/__init__.py,sha256=i2Lbq_VxIgppaqwkxG0_H35dRfcjJ4mCYWjprOf4hHo,7318
3
- megfile/cli.py,sha256=miI1fEHY3zBxWwwN5F5AHjO14-AI920oPxD4sfi94gY,23465
4
- megfile/config.py,sha256=_SkJRaVWUdfW1Q9uX0vao-6YVQKJtfej22Z8DykuRps,2331
5
- megfile/errors.py,sha256=KyHvK3CgiSgiXT_5kqKa7Nb8Bdwh7U6mBh_H7Gj-Z84,14125
3
+ megfile/cli.py,sha256=0Sgbz3jeUryVll9Aa6R0MpJdQJUGENvz55YF7Jm1Uxc,23482
4
+ megfile/config.py,sha256=k52eO9YUyYRJ0-bsscAXcfEt8xIAHGOHdLSnEJf6z7k,2411
5
+ megfile/errors.py,sha256=a55qKQgyfiLmV-qnojUFzq2gu9JXpj3ZiC2qVaWyUTA,14160
6
6
  megfile/fs.py,sha256=dgj5fW-EEzQNdjMF2tkB5DjXu3iHQbtLi5PSIMxR8fc,11966
7
7
  megfile/fs_path.py,sha256=Ffvukc176beH5aQMZXXtwH6ApwLYXPViCIUP0pijgT0,41590
8
8
  megfile/hdfs.py,sha256=latguOuuzAmg-yWOy3Sm723CJ0ybN_eSHRubVNqhcMU,9202
@@ -10,16 +10,16 @@ megfile/hdfs_path.py,sha256=0XLtABufwqL-y8igOxzOJz6zOGppuBp2f2SwXIMvvYg,27299
10
10
  megfile/http.py,sha256=2Z2yqyhU-zcJCJwSNyBsxsZ7f2FT9X6fcednsbHDsFM,2025
11
11
  megfile/http_path.py,sha256=BhMNjQVB85IaCGGIKzgEfY73mAVdCzJP08W1RuGeMRA,16119
12
12
  megfile/interfaces.py,sha256=7C53Q2FAVFmOEnplfplvWqHab29HJE5RQnpfdb4loVY,8679
13
- megfile/pathlike.py,sha256=vKuCMlSAPYNSojp03wEj2i3Cq3E3ROp_-UkkdgBElws,30802
13
+ megfile/pathlike.py,sha256=5VAKIArm2UqrpMBJMoNAEydFxLd1mjCZ8iQnKFUIYu0,31274
14
14
  megfile/s3.py,sha256=7SdfLjAePVh-bpRyuj566VB4Qa7KP86rCJGzYANR7wQ,13008
15
- megfile/s3_path.py,sha256=YvIRVI4d6kd2m2wvcIqiu43nPOYZpaPgG9-BospF81w,93803
15
+ megfile/s3_path.py,sha256=kOrP45zQbxCxNQcoovd060QARkP8QWYKd8BQGfxGY2g,95447
16
16
  megfile/sftp.py,sha256=vyDnYXX3i1j2fhXMC8YCeX-66MDb9wrBQQjQVhZx0uo,13004
17
17
  megfile/sftp_path.py,sha256=4tByWvUJK1KBJoa3t5aoWYnZpaRWN9nQIE6ZyiGHrbk,53519
18
18
  megfile/smart.py,sha256=Vr4R7HpjXjt587KOc2-1QGbQ5EsZ48YRzCaK0rz3IS0,36108
19
- megfile/smart_path.py,sha256=22ZTrA7j9Kd5PJsUJOxBdGg0Uu5FxwdT_XQjQDxUHo4,7637
19
+ megfile/smart_path.py,sha256=Wsn6fR9g7NTwNwwvZ_0H39NLHIlOLnCqK-ZY0n5CvKk,7812
20
20
  megfile/stdio.py,sha256=UYe-h440Wc4f5COOzOTG1svnp5nFzrfpixehJ0_0_NY,653
21
21
  megfile/stdio_path.py,sha256=7jzVdreamO18yBWZM7Pp71cO7GmrYb0M0qyQde2Ypq4,2706
22
- megfile/version.py,sha256=kh8D3nOB4xuR3KqckCcukx60UxptlmvEx5kjmgZinIA,19
22
+ megfile/version.py,sha256=XtGruYz10E7g9ijesLiQ9efrLMwPQjA29gsjMfo552o,25
23
23
  megfile/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  megfile/lib/base_prefetch_reader.py,sha256=CaYWuiKmlk4Utr0IFDPwPC58wV2jBAhqpxhwhRHc734,13652
25
25
  megfile/lib/combine_reader.py,sha256=uSzo3PmhD5ck6_Vv6dFU5vVx4boeA97VS-puPyhF_BE,4657
@@ -37,19 +37,19 @@ megfile/lib/s3_cached_handler.py,sha256=QrQKck06ye16o7GD71T-fVCseKlOhsxp82LtBTtA
37
37
  megfile/lib/s3_limited_seekable_writer.py,sha256=v-e7rfFBfWCSQVtJIaFHM_i0Hb1FkfVLHlhawo5MOIk,6358
38
38
  megfile/lib/s3_memory_handler.py,sha256=NGKWbI4LG2cmV06CP7KOVPqS_BNpm3ApqKi5ibgIBvQ,4208
39
39
  megfile/lib/s3_pipe_handler.py,sha256=DY1UTNCq8oD3QWXNb4orOiz3EoEAo6dhwmZZdk6h1bU,3694
40
- megfile/lib/s3_prefetch_reader.py,sha256=YZA6JOQXcioREh_z1E-kZ2WRPTm02v0dCEVqyaOMHns,4287
40
+ megfile/lib/s3_prefetch_reader.py,sha256=gjnnYI95LFwxpneDFfLBzw8gvT1Vc8yJJlBL101oysI,4501
41
41
  megfile/lib/s3_share_cache_reader.py,sha256=jhGL1B6NPv68cQnW1Jf7ey-zTQ8XfiJg5ILDNgRWHy0,3671
42
42
  megfile/lib/shadow_handler.py,sha256=TntewlvIW9ZxCfmqASDQREHoiZ8v42faOe9sovQYQz0,2779
43
43
  megfile/lib/stdio_handler.py,sha256=IDdgENLQlhigEwkLL4zStueVSzdWg7xVcTF_koof_Ek,1987
44
44
  megfile/lib/url.py,sha256=ER32pWy9Q2MAk3TraAaNEBWIqUeBmLuM57ol2cs7-Ks,103
45
- megfile/utils/__init__.py,sha256=NfO5vNxfeceGvMB3dgZNudyPFTmPY096JbC4iYroX6o,9003
45
+ megfile/utils/__init__.py,sha256=RAj8dAJZX5TkWKJu3Ip78uhA5XZ8wpir61eCm6bAnd4,10874
46
46
  megfile/utils/mutex.py,sha256=asb8opGLgK22RiuBJUnfsvB8LnMmodP8KzCVHKmQBWA,2561
47
47
  scripts/convert_results_to_sarif.py,sha256=nDiOfsedb22Ps7ZodmYdlXZlxv54fRxCQgOZsB2OkNk,2833
48
48
  scripts/generate_file.py,sha256=-mTcBiqiQ1juvqojVfVZ-uZWgpANHJNdhrF7s68zNfc,10903
49
- megfile-3.1.5.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
50
- megfile-3.1.5.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
51
- megfile-3.1.5.dist-info/METADATA,sha256=jPBOY1WWbh-Jxdam48x2RxcXGVV2liPW4kQTw8VtBl0,9178
52
- megfile-3.1.5.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
53
- megfile-3.1.5.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
54
- megfile-3.1.5.dist-info/top_level.txt,sha256=oTnYXo1Z3V61qSWAKtnY9RkDgRSHvfRN38FQae6E0W0,50
55
- megfile-3.1.5.dist-info/RECORD,,
49
+ megfile-3.1.6.post1.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
50
+ megfile-3.1.6.post1.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
51
+ megfile-3.1.6.post1.dist-info/METADATA,sha256=AEZWwtG0zg1mZzAIyM9YHZ5JmbS0Bwc6YCMsGFrTYDo,9184
52
+ megfile-3.1.6.post1.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
53
+ megfile-3.1.6.post1.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
54
+ megfile-3.1.6.post1.dist-info/top_level.txt,sha256=oTnYXo1Z3V61qSWAKtnY9RkDgRSHvfRN38FQae6E0W0,50
55
+ megfile-3.1.6.post1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.5.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5