megfile 4.1.8.post1__py3-none-any.whl → 4.2.1__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 +3 -4
- megfile/s3_path.py +38 -34
- megfile/version.py +1 -1
- {megfile-4.1.8.post1.dist-info → megfile-4.2.1.dist-info}/METADATA +1 -1
- {megfile-4.1.8.post1.dist-info → megfile-4.2.1.dist-info}/RECORD +10 -10
- {megfile-4.1.8.post1.dist-info → megfile-4.2.1.dist-info}/WHEEL +0 -0
- {megfile-4.1.8.post1.dist-info → megfile-4.2.1.dist-info}/entry_points.txt +0 -0
- {megfile-4.1.8.post1.dist-info → megfile-4.2.1.dist-info}/licenses/LICENSE +0 -0
- {megfile-4.1.8.post1.dist-info → megfile-4.2.1.dist-info}/licenses/LICENSE.pyre +0 -0
- {megfile-4.1.8.post1.dist-info → megfile-4.2.1.dist-info}/top_level.txt +0 -0
megfile/cli.py
CHANGED
|
@@ -70,17 +70,16 @@ def cli(debug, log_level):
|
|
|
70
70
|
"""
|
|
71
71
|
options["debug"] = debug
|
|
72
72
|
options["log_level"] = log_level or ("DEBUG" if debug else "INFO")
|
|
73
|
+
if not debug:
|
|
74
|
+
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
73
75
|
set_log_level(options["log_level"])
|
|
74
76
|
|
|
75
77
|
|
|
76
78
|
def safe_cli(): # pragma: no cover
|
|
77
|
-
debug = options.get("debug", False)
|
|
78
|
-
if not debug:
|
|
79
|
-
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
80
79
|
try:
|
|
81
80
|
cli()
|
|
82
81
|
except Exception as e:
|
|
83
|
-
if debug:
|
|
82
|
+
if options.get("debug", False):
|
|
84
83
|
raise
|
|
85
84
|
else:
|
|
86
85
|
click.echo(f"\n[{type(e).__name__}] {e}", err=True)
|
megfile/s3_path.py
CHANGED
|
@@ -605,6 +605,8 @@ def _s3_glob_stat_single_path(
|
|
|
605
605
|
for content in resp.get("Contents", []):
|
|
606
606
|
path = s3_path_join(f"{protocol}://", bucket, content["Key"])
|
|
607
607
|
if not search_dir and pattern.match(path):
|
|
608
|
+
if path.endswith("/"):
|
|
609
|
+
continue
|
|
608
610
|
yield FileEntry(S3Path(path).name, path, _make_stat(content))
|
|
609
611
|
dirname = os.path.dirname(path)
|
|
610
612
|
while dirname not in dirnames and dirname != top_dir:
|
|
@@ -1674,15 +1676,18 @@ class S3Path(URIPath):
|
|
|
1674
1676
|
:returns: True if path is s3 file, else False
|
|
1675
1677
|
"""
|
|
1676
1678
|
s3_url = self.path_with_protocol
|
|
1679
|
+
bucket, key = parse_s3_url(s3_url)
|
|
1680
|
+
if not bucket or not key or key.endswith("/"):
|
|
1681
|
+
# s3://, s3:///key, s3://bucket, s3://bucket/prefix/
|
|
1682
|
+
return False
|
|
1683
|
+
|
|
1677
1684
|
if followlinks:
|
|
1678
1685
|
try:
|
|
1679
1686
|
s3_url = self.readlink().path_with_protocol
|
|
1687
|
+
bucket, key = parse_s3_url(s3_url)
|
|
1680
1688
|
except S3NotALinkError:
|
|
1681
1689
|
pass
|
|
1682
|
-
|
|
1683
|
-
if not bucket or not key or key.endswith("/"):
|
|
1684
|
-
# s3://, s3:///key, s3://bucket, s3://bucket/prefix/
|
|
1685
|
-
return False
|
|
1690
|
+
|
|
1686
1691
|
try:
|
|
1687
1692
|
self._client.head_object(Bucket=bucket, Key=key)
|
|
1688
1693
|
except Exception as error:
|
|
@@ -1827,18 +1832,18 @@ class S3Path(URIPath):
|
|
|
1827
1832
|
)
|
|
1828
1833
|
if not key:
|
|
1829
1834
|
raise UnsupportedError("Remove bucket", self.path_with_protocol)
|
|
1830
|
-
if not self.exists():
|
|
1831
|
-
if missing_ok:
|
|
1832
|
-
return
|
|
1833
|
-
raise S3FileNotFoundError(
|
|
1834
|
-
"No such file or directory: %r" % self.path_with_protocol
|
|
1835
|
-
)
|
|
1836
1835
|
|
|
1837
1836
|
client = self._client
|
|
1837
|
+
if self.is_file():
|
|
1838
|
+
try:
|
|
1839
|
+
with raise_s3_error(self.path_with_protocol):
|
|
1840
|
+
client.delete_object(Bucket=bucket, Key=key)
|
|
1841
|
+
except S3FileNotFoundError:
|
|
1842
|
+
if not missing_ok:
|
|
1843
|
+
raise
|
|
1844
|
+
return
|
|
1845
|
+
|
|
1838
1846
|
with raise_s3_error(self.path_with_protocol):
|
|
1839
|
-
if self.is_file():
|
|
1840
|
-
client.delete_object(Bucket=bucket, Key=key)
|
|
1841
|
-
return
|
|
1842
1847
|
prefix = _become_prefix(key)
|
|
1843
1848
|
total_count, error_count = 0, 0
|
|
1844
1849
|
for resp in _list_objects_recursive(client, bucket, prefix):
|
|
@@ -1889,6 +1894,10 @@ class S3Path(URIPath):
|
|
|
1889
1894
|
% (self.path_with_protocol, total_count, error_count)
|
|
1890
1895
|
)
|
|
1891
1896
|
raise S3UnknownError(Exception(error_msg), self.path_with_protocol)
|
|
1897
|
+
if total_count == 0 and not missing_ok:
|
|
1898
|
+
raise S3FileNotFoundError(
|
|
1899
|
+
"No such file or directory: %r" % self.path_with_protocol
|
|
1900
|
+
)
|
|
1892
1901
|
|
|
1893
1902
|
def rename(self, dst_path: PathLike, overwrite: bool = True) -> "S3Path":
|
|
1894
1903
|
"""
|
|
@@ -1960,6 +1969,7 @@ class S3Path(URIPath):
|
|
|
1960
1969
|
)
|
|
1961
1970
|
|
|
1962
1971
|
prefix = _become_prefix(key)
|
|
1972
|
+
protocol = self._protocol_with_profile
|
|
1963
1973
|
client = self._client
|
|
1964
1974
|
|
|
1965
1975
|
def suppress_error_callback(e):
|
|
@@ -1970,13 +1980,13 @@ class S3Path(URIPath):
|
|
|
1970
1980
|
with raise_s3_error(self.path_with_protocol, suppress_error_callback):
|
|
1971
1981
|
for resp in _list_objects_recursive(client, bucket, prefix):
|
|
1972
1982
|
for content in resp.get("Contents", []):
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
)
|
|
1983
|
+
if content["Key"].endswith("/"):
|
|
1984
|
+
continue
|
|
1985
|
+
path = s3_path_join(f"{protocol}://", bucket, content["Key"])
|
|
1976
1986
|
|
|
1977
1987
|
if followlinks:
|
|
1978
1988
|
try:
|
|
1979
|
-
origin_path = self.from_path(
|
|
1989
|
+
origin_path = self.from_path(path).readlink()
|
|
1980
1990
|
yield FileEntry(
|
|
1981
1991
|
origin_path.name,
|
|
1982
1992
|
origin_path.path_with_protocol,
|
|
@@ -1986,9 +1996,7 @@ class S3Path(URIPath):
|
|
|
1986
1996
|
except S3NotALinkError:
|
|
1987
1997
|
pass
|
|
1988
1998
|
|
|
1989
|
-
yield FileEntry(
|
|
1990
|
-
S3Path(full_path).name, full_path, _make_stat(content)
|
|
1991
|
-
)
|
|
1999
|
+
yield FileEntry(S3Path(path).name, path, _make_stat(content))
|
|
1992
2000
|
|
|
1993
2001
|
return _create_missing_ok_generator(
|
|
1994
2002
|
create_generator(),
|
|
@@ -2016,17 +2024,15 @@ class S3Path(URIPath):
|
|
|
2016
2024
|
# we need to wrap the iterator in another function
|
|
2017
2025
|
def create_generator() -> Iterator[FileEntry]:
|
|
2018
2026
|
prefix = _become_prefix(key)
|
|
2027
|
+
protocol = self._protocol_with_profile
|
|
2019
2028
|
client = self._client
|
|
2020
2029
|
|
|
2021
|
-
def generate_s3_path(protocol: str, bucket: str, key: str) -> str:
|
|
2022
|
-
return "%s://%s/%s" % (protocol, bucket, key)
|
|
2023
|
-
|
|
2024
2030
|
if not bucket and not key: # list buckets
|
|
2025
2031
|
response = client.list_buckets()
|
|
2026
2032
|
for content in response["Buckets"]:
|
|
2027
2033
|
yield FileEntry(
|
|
2028
2034
|
content["Name"],
|
|
2029
|
-
f"{
|
|
2035
|
+
f"{protocol}://{content['Name']}",
|
|
2030
2036
|
StatResult(
|
|
2031
2037
|
ctime=content["CreationDate"].timestamp(),
|
|
2032
2038
|
isdir=True,
|
|
@@ -2039,21 +2045,17 @@ class S3Path(URIPath):
|
|
|
2039
2045
|
for common_prefix in resp.get("CommonPrefixes", []):
|
|
2040
2046
|
yield FileEntry(
|
|
2041
2047
|
common_prefix["Prefix"][len(prefix) : -1],
|
|
2042
|
-
|
|
2043
|
-
self._protocol_with_profile,
|
|
2044
|
-
bucket,
|
|
2045
|
-
common_prefix["Prefix"],
|
|
2046
|
-
),
|
|
2048
|
+
f"{protocol}://{bucket}/{common_prefix['Prefix']}",
|
|
2047
2049
|
StatResult(isdir=True, extra=common_prefix),
|
|
2048
2050
|
)
|
|
2049
2051
|
for content in resp.get("Contents", []):
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2052
|
+
if content["Key"].endswith("/"):
|
|
2053
|
+
continue
|
|
2054
|
+
path = f"{protocol}://{bucket}/{content['Key']}"
|
|
2053
2055
|
yield FileEntry( # pytype: disable=wrong-arg-types
|
|
2054
2056
|
content["Key"][len(prefix) :],
|
|
2055
|
-
|
|
2056
|
-
_make_stat_without_metadata(content, self.from_path(
|
|
2057
|
+
path,
|
|
2058
|
+
_make_stat_without_metadata(content, self.from_path(path)),
|
|
2057
2059
|
)
|
|
2058
2060
|
|
|
2059
2061
|
def missing_ok_generator():
|
|
@@ -2220,6 +2222,8 @@ class S3Path(URIPath):
|
|
|
2220
2222
|
for common_prefix in resp.get("CommonPrefixes", []):
|
|
2221
2223
|
dirs.append(common_prefix["Prefix"][:-1])
|
|
2222
2224
|
for content in resp.get("Contents", []):
|
|
2225
|
+
if content["Key"].endswith("/"):
|
|
2226
|
+
continue
|
|
2223
2227
|
files.append(content["Key"])
|
|
2224
2228
|
|
|
2225
2229
|
dirs = sorted(dirs)
|
megfile/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = "4.1
|
|
1
|
+
VERSION = "4.2.1"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
megfile/__init__.py,sha256=7oEfu410CFKzDWZ9RjL5xEJ1gtkJkTfvPrL_7TWdJuY,7366
|
|
2
|
-
megfile/cli.py,sha256=
|
|
2
|
+
megfile/cli.py,sha256=VxY0__M19Ti_S7ZIozp9l0FxvdLwdd6eQL-wfpYOi_0,29160
|
|
3
3
|
megfile/config.py,sha256=2MMj5QkhlDJQFZRbCQL2c9iDdeMAVctiaPszRBkg5vM,3988
|
|
4
4
|
megfile/errors.py,sha256=aw4BX-pU1uj0-dNc6Tq-IeSwK_PWJNi2ZL5ZcRSo7aQ,14739
|
|
5
5
|
megfile/fs.py,sha256=KMEqAE35alpcxiy6du5nPFYcaorhUM_kPJMah3q76ng,19160
|
|
@@ -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=
|
|
14
|
+
megfile/s3_path.py,sha256=NKOJLxy1gxdOc-jdEvxNl45tham5un8YWmZC-CZXHuU,93663
|
|
15
15
|
megfile/sftp.py,sha256=uBcLQs-j6Q-q-sWAdd-pgi5Qmb_kq7boJM-0sCfcNO0,26540
|
|
16
16
|
megfile/sftp_path.py,sha256=CgirHWmNdXdqyIL9ufmlaMpwFhlkQVZhqmfvjUaj7qU,43845
|
|
17
17
|
megfile/smart.py,sha256=Miz3jyLKmwWBja-8GrSzrumpTarPrFPqXaFQJKwrK1Y,36627
|
|
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=
|
|
21
|
+
megfile/version.py,sha256=e0k-2Nn8dpoGmVJ3Wg03fcRMzM9q9jfKeY7f3OkI7LE,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.1.
|
|
47
|
-
megfile-4.1.
|
|
48
|
-
megfile-4.1.
|
|
49
|
-
megfile-4.1.
|
|
50
|
-
megfile-4.1.
|
|
51
|
-
megfile-4.1.
|
|
52
|
-
megfile-4.1.
|
|
46
|
+
megfile-4.2.1.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
47
|
+
megfile-4.2.1.dist-info/licenses/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
|
|
48
|
+
megfile-4.2.1.dist-info/METADATA,sha256=8-Gzye2STZTocHieLky8XR0nAae8sHEmanRVeTWKWYM,9595
|
|
49
|
+
megfile-4.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
50
|
+
megfile-4.2.1.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
|
|
51
|
+
megfile-4.2.1.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
|
|
52
|
+
megfile-4.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|