megfile 4.2.0__py3-none-any.whl → 4.2.2__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/errors.py CHANGED
@@ -9,6 +9,10 @@ from typing import Callable, Optional
9
9
  import botocore.exceptions
10
10
  import requests.exceptions
11
11
  import urllib3.exceptions
12
+ from boto3.exceptions import ( # TODO: test different boto3 version
13
+ S3TransferFailedError,
14
+ S3UploadFailedError,
15
+ )
12
16
  from botocore.exceptions import ClientError, NoCredentialsError, ParamValidationError
13
17
  from requests.exceptions import HTTPError
14
18
 
@@ -402,6 +406,19 @@ def translate_s3_error(s3_error: Exception, s3_url: PathLike) -> Exception:
402
406
  return S3UnknownError(s3_error, s3_url)
403
407
  elif isinstance(s3_error, NoCredentialsError):
404
408
  return S3ConfigError(str(s3_error))
409
+ elif isinstance(s3_error, (S3UploadFailedError, S3TransferFailedError)):
410
+ if "NoSuchBucket" in str(s3_error):
411
+ return S3BucketNotFoundError("No such bucket: %r" % s3_url)
412
+ elif "NoSuchKey" in str(s3_error):
413
+ return S3FileNotFoundError("No such file: %r" % s3_url)
414
+ elif "InvalidAccessKeyId" in str(s3_error) or "SignatureDoesNotMatch" in str(
415
+ s3_error
416
+ ):
417
+ return S3ConfigError("Invalid access key id: %r" % s3_url)
418
+ elif "InvalidRange" in str(s3_error):
419
+ return S3InvalidRangeError("Invalid range: %r" % s3_url)
420
+ elif "AccessDenied" in str(s3_error):
421
+ return S3PermissionError("Access denied: %r" % s3_url)
405
422
  return S3UnknownError(s3_error, s3_url)
406
423
 
407
424
 
megfile/s3_path.py CHANGED
@@ -1201,6 +1201,10 @@ def s3_upload(
1201
1201
  src_path = FSPath(src_url)
1202
1202
  if followlinks and src_path.is_symlink():
1203
1203
  src_path = src_path.readlink()
1204
+ if not src_path.exists():
1205
+ raise FileNotFoundError("No such file or directory: %r" % src_url)
1206
+ elif src_path.is_dir():
1207
+ raise IsADirectoryError("Is a directory: %r" % src_url)
1204
1208
 
1205
1209
  dst_bucket, dst_key = parse_s3_url(dst_url)
1206
1210
  if not dst_bucket:
@@ -1212,8 +1216,8 @@ def s3_upload(
1212
1216
  return
1213
1217
 
1214
1218
  client = get_s3_client_with_cache(profile_name=S3Path(dst_url)._profile_name)
1215
- upload_fileobj = patch_method(
1216
- client.upload_fileobj, max_retries=max_retries, should_retry=s3_should_retry
1219
+ upload_file = patch_method(
1220
+ client.upload_file, max_retries=max_retries, should_retry=s3_should_retry
1217
1221
  )
1218
1222
 
1219
1223
  transfer_config = TransferConfig(
@@ -1221,9 +1225,9 @@ def s3_upload(
1221
1225
  max_concurrency=GLOBAL_MAX_WORKERS,
1222
1226
  multipart_chunksize=WRITER_BLOCK_SIZE,
1223
1227
  )
1224
- with open(src_path.path_without_protocol, "rb") as src, raise_s3_error(dst_url):
1225
- upload_fileobj(
1226
- src,
1228
+ with raise_s3_error(dst_url):
1229
+ upload_file(
1230
+ src_path.path_without_protocol,
1227
1231
  Bucket=dst_bucket,
1228
1232
  Key=dst_key,
1229
1233
  Callback=callback,
@@ -1676,15 +1680,18 @@ class S3Path(URIPath):
1676
1680
  :returns: True if path is s3 file, else False
1677
1681
  """
1678
1682
  s3_url = self.path_with_protocol
1683
+ bucket, key = parse_s3_url(s3_url)
1684
+ if not bucket or not key or key.endswith("/"):
1685
+ # s3://, s3:///key, s3://bucket, s3://bucket/prefix/
1686
+ return False
1687
+
1679
1688
  if followlinks:
1680
1689
  try:
1681
1690
  s3_url = self.readlink().path_with_protocol
1691
+ bucket, key = parse_s3_url(s3_url)
1682
1692
  except S3NotALinkError:
1683
1693
  pass
1684
- bucket, key = parse_s3_url(s3_url)
1685
- if not bucket or not key or key.endswith("/"):
1686
- # s3://, s3:///key, s3://bucket, s3://bucket/prefix/
1687
- return False
1694
+
1688
1695
  try:
1689
1696
  self._client.head_object(Bucket=bucket, Key=key)
1690
1697
  except Exception as error:
@@ -1829,18 +1836,18 @@ class S3Path(URIPath):
1829
1836
  )
1830
1837
  if not key:
1831
1838
  raise UnsupportedError("Remove bucket", self.path_with_protocol)
1832
- if not self.exists():
1833
- if missing_ok:
1834
- return
1835
- raise S3FileNotFoundError(
1836
- "No such file or directory: %r" % self.path_with_protocol
1837
- )
1838
1839
 
1839
1840
  client = self._client
1841
+ if self.is_file():
1842
+ try:
1843
+ with raise_s3_error(self.path_with_protocol):
1844
+ client.delete_object(Bucket=bucket, Key=key)
1845
+ except S3FileNotFoundError:
1846
+ if not missing_ok:
1847
+ raise
1848
+ return
1849
+
1840
1850
  with raise_s3_error(self.path_with_protocol):
1841
- if self.is_file():
1842
- client.delete_object(Bucket=bucket, Key=key)
1843
- return
1844
1851
  prefix = _become_prefix(key)
1845
1852
  total_count, error_count = 0, 0
1846
1853
  for resp in _list_objects_recursive(client, bucket, prefix):
@@ -1891,6 +1898,10 @@ class S3Path(URIPath):
1891
1898
  % (self.path_with_protocol, total_count, error_count)
1892
1899
  )
1893
1900
  raise S3UnknownError(Exception(error_msg), self.path_with_protocol)
1901
+ if total_count == 0 and not missing_ok:
1902
+ raise S3FileNotFoundError(
1903
+ "No such file or directory: %r" % self.path_with_protocol
1904
+ )
1894
1905
 
1895
1906
  def rename(self, dst_path: PathLike, overwrite: bool = True) -> "S3Path":
1896
1907
  """
megfile/smart.py CHANGED
@@ -308,8 +308,18 @@ def _default_copy_func(
308
308
 
309
309
 
310
310
  def _get_copy_func(src_protocol, dst_protocol):
311
- if src_protocol.startswith("s3+") and src_protocol == dst_protocol:
311
+ def _is_s3_plus(protocol: str):
312
+ return protocol.startswith("s3+")
313
+
314
+ def _is_s3_or_s3_plus(protocol: str):
315
+ return protocol.startswith("s3+") or protocol == "s3"
316
+
317
+ if _is_s3_plus(src_protocol) and src_protocol == dst_protocol:
312
318
  src_protocol = dst_protocol = "s3"
319
+ elif _is_s3_plus(src_protocol) and not _is_s3_or_s3_plus(dst_protocol):
320
+ src_protocol = "s3"
321
+ elif _is_s3_plus(dst_protocol) and not _is_s3_or_s3_plus(src_protocol):
322
+ dst_protocol = "s3"
313
323
 
314
324
  try:
315
325
  return _copy_funcs[src_protocol][dst_protocol]
megfile/version.py CHANGED
@@ -1 +1 @@
1
- VERSION = "4.2.0"
1
+ VERSION = "4.2.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: megfile
3
- Version: 4.2.0
3
+ Version: 4.2.2
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
@@ -24,7 +24,7 @@ License-File: LICENSE.pyre
24
24
  Requires-Dist: boto3
25
25
  Requires-Dist: botocore>=1.13.0
26
26
  Requires-Dist: requests
27
- Requires-Dist: paramiko
27
+ Requires-Dist: paramiko<4.0.0
28
28
  Requires-Dist: tqdm
29
29
  Requires-Dist: pyyaml
30
30
  Provides-Extra: hdfs
@@ -1,7 +1,7 @@
1
1
  megfile/__init__.py,sha256=7oEfu410CFKzDWZ9RjL5xEJ1gtkJkTfvPrL_7TWdJuY,7366
2
2
  megfile/cli.py,sha256=VxY0__M19Ti_S7ZIozp9l0FxvdLwdd6eQL-wfpYOi_0,29160
3
3
  megfile/config.py,sha256=2MMj5QkhlDJQFZRbCQL2c9iDdeMAVctiaPszRBkg5vM,3988
4
- megfile/errors.py,sha256=aw4BX-pU1uj0-dNc6Tq-IeSwK_PWJNi2ZL5ZcRSo7aQ,14739
4
+ megfile/errors.py,sha256=cGSYyB7VBRKi1Gehgt9IO-wDvtzICV4XgKOkoMvLU5w,15583
5
5
  megfile/fs.py,sha256=KMEqAE35alpcxiy6du5nPFYcaorhUM_kPJMah3q76ng,19160
6
6
  megfile/fs_path.py,sha256=Hozl9LAJ8EMuSWBSZXGj2GNmPZ1sJp9PZs-7hPrLgm8,39341
7
7
  megfile/hdfs.py,sha256=owXr4d3j1frCvlbhmhENcSBnKKDky5cJZzWLOF4ZJMo,13251
@@ -11,14 +11,14 @@ megfile/http_path.py,sha256=08OmzmRMyLSyq1Yr1K2HbzexesURJrIoA6AibwYzUiA,13844
11
11
  megfile/interfaces.py,sha256=p4UvVZpeLx5djd6bqqDaygIx_s-_AxIVj-gudTch4JE,8467
12
12
  megfile/pathlike.py,sha256=3Hnw-fn6RcIe9iPrJt00QdHSA--UfDyxnVBuZ_ymYYQ,31278
13
13
  megfile/s3.py,sha256=abBxnI7RIyn7n7qjGszP1VruYd6Gi9I8QnUOvsHkx1Y,16325
14
- megfile/s3_path.py,sha256=nA1FXFwfhSvZN8W0mF2PKGbnaTDouZfp6anUZkxvOBc,93449
14
+ megfile/s3_path.py,sha256=fzqXahIEKGbyArU-2Yl5YpczwkImUiZy7Y1RYQOKNKM,93827
15
15
  megfile/sftp.py,sha256=uBcLQs-j6Q-q-sWAdd-pgi5Qmb_kq7boJM-0sCfcNO0,26540
16
16
  megfile/sftp_path.py,sha256=CgirHWmNdXdqyIL9ufmlaMpwFhlkQVZhqmfvjUaj7qU,43845
17
- megfile/smart.py,sha256=Miz3jyLKmwWBja-8GrSzrumpTarPrFPqXaFQJKwrK1Y,36627
17
+ megfile/smart.py,sha256=GnabQVb_NU7a-etKfF-NgpJ9JM2rT0uZBeA9UoNz_wM,37014
18
18
  megfile/smart_path.py,sha256=Up_6xNZ2019iSzMn_JAU_1H--z-AP6O7SxdXGdeTG0c,7659
19
19
  megfile/stdio.py,sha256=ZwxsnJNJYIT7Iyg5pIw4qiyH8bszG6oAhEJuR-hXGG4,658
20
20
  megfile/stdio_path.py,sha256=cxaDr8rtisTPnN-rjtaEpqQnshwiqwXFUJBM9xWY7Cg,2711
21
- megfile/version.py,sha256=nmN7kc0bNHgtVq4jv4MJKEo-L3X7QgGHAv_z6zkMVSQ,19
21
+ megfile/version.py,sha256=xnzpVSLKRvpgVFWjV-1xKKQitlJEcAepuzOjV7CqQ6I,19
22
22
  megfile/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  megfile/lib/base_prefetch_reader.py,sha256=uxVwYknOjc8hLF7q_T2QKMsBqFcrf411ZsuK25CN1eQ,12848
24
24
  megfile/lib/combine_reader.py,sha256=Kp2wEloOUpTlIU7dve87MBpSzmIM-F9OtpTawAjFkiU,4828
@@ -43,10 +43,10 @@ megfile/lib/stdio_handler.py,sha256=IDdgENLQlhigEwkLL4zStueVSzdWg7xVcTF_koof_Ek,
43
43
  megfile/lib/url.py,sha256=ER32pWy9Q2MAk3TraAaNEBWIqUeBmLuM57ol2cs7-Ks,103
44
44
  megfile/utils/__init__.py,sha256=pawmXnCNokWLj338a60b_hK21koYavpEiEohZhsOaGQ,10156
45
45
  megfile/utils/mutex.py,sha256=asb8opGLgK22RiuBJUnfsvB8LnMmodP8KzCVHKmQBWA,2561
46
- megfile-4.2.0.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
47
- megfile-4.2.0.dist-info/licenses/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
48
- megfile-4.2.0.dist-info/METADATA,sha256=0IuIzy3B0sO0YhPrMdEK5kCkK16K1ZCX6w3vZO-SlB4,9595
49
- megfile-4.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
50
- megfile-4.2.0.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
51
- megfile-4.2.0.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
52
- megfile-4.2.0.dist-info/RECORD,,
46
+ megfile-4.2.2.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
47
+ megfile-4.2.2.dist-info/licenses/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
48
+ megfile-4.2.2.dist-info/METADATA,sha256=GCTiJb_unoYia-PwLFfqjOhm-7hjU73R-pJIpDChSAk,9601
49
+ megfile-4.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
50
+ megfile-4.2.2.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
51
+ megfile-4.2.2.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
52
+ megfile-4.2.2.dist-info/RECORD,,