megfile 2.2.0__py3-none-any.whl → 2.2.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.
- megfile/cli.py +6 -5
- megfile/errors.py +4 -1
- megfile/lib/s3_prefetch_reader.py +4 -2
- megfile/s3_path.py +22 -4
- megfile/sftp_path.py +27 -16
- megfile/version.py +1 -1
- {megfile-2.2.0.dist-info → megfile-2.2.0.post1.dist-info}/METADATA +1 -1
- {megfile-2.2.0.dist-info → megfile-2.2.0.post1.dist-info}/RECORD +13 -13
- {megfile-2.2.0.dist-info → megfile-2.2.0.post1.dist-info}/LICENSE +0 -0
- {megfile-2.2.0.dist-info → megfile-2.2.0.post1.dist-info}/LICENSE.pyre +0 -0
- {megfile-2.2.0.dist-info → megfile-2.2.0.post1.dist-info}/WHEEL +0 -0
- {megfile-2.2.0.dist-info → megfile-2.2.0.post1.dist-info}/entry_points.txt +0 -0
- {megfile-2.2.0.dist-info → megfile-2.2.0.post1.dist-info}/top_level.txt +0 -0
megfile/cli.py
CHANGED
|
@@ -319,13 +319,14 @@ def cat(path: str):
|
|
|
319
319
|
help='print the first NUM lines')
|
|
320
320
|
def head(path: str, lines: int):
|
|
321
321
|
with smart_open(path, 'rb') as f:
|
|
322
|
-
f.seek(0, os.SEEK_END)
|
|
323
|
-
file_size = f.tell()
|
|
324
|
-
f.seek(0, os.SEEK_SET)
|
|
325
322
|
for _ in range(lines):
|
|
326
|
-
|
|
327
|
-
|
|
323
|
+
try:
|
|
324
|
+
content = f.readline()
|
|
325
|
+
if not content:
|
|
326
|
+
break
|
|
327
|
+
except EOFError:
|
|
328
328
|
break
|
|
329
|
+
click.echo(content.strip(b'\n'))
|
|
329
330
|
|
|
330
331
|
|
|
331
332
|
@cli.command(
|
megfile/errors.py
CHANGED
|
@@ -139,6 +139,9 @@ def patch_method(
|
|
|
139
139
|
result = func(*args, **kwargs)
|
|
140
140
|
if after_callback is not None:
|
|
141
141
|
result = after_callback(result, *args, **kwargs)
|
|
142
|
+
if retries > 1:
|
|
143
|
+
_logger.info(
|
|
144
|
+
f'Error already fixed by retry {retries - 1} times')
|
|
142
145
|
return result
|
|
143
146
|
except Exception as error:
|
|
144
147
|
if not should_retry(error):
|
|
@@ -148,7 +151,7 @@ def patch_method(
|
|
|
148
151
|
if retries == max_retries:
|
|
149
152
|
raise
|
|
150
153
|
retry_interval = min(0.1 * 2**retries, 30)
|
|
151
|
-
_logger.
|
|
154
|
+
_logger.info(
|
|
152
155
|
'unknown error encountered: %s, retry in %0.1f seconds after %d tries'
|
|
153
156
|
% (full_error_message(error), retry_interval, retries))
|
|
154
157
|
time.sleep(retry_interval)
|
|
@@ -361,8 +361,10 @@ class S3PrefetchReader(Readable, Seekable):
|
|
|
361
361
|
|
|
362
362
|
range_str = 'bytes=%d-%d' % (
|
|
363
363
|
index * self._block_size, (index + 1) * self._block_size - 1)
|
|
364
|
-
|
|
364
|
+
response = self._client.get_object(
|
|
365
365
|
Bucket=self._bucket, Key=self._key, Range=range_str)
|
|
366
|
+
response['Body'] = BytesIO(response['Body'].read())
|
|
367
|
+
return response
|
|
366
368
|
|
|
367
369
|
fetch_response = patch_method(
|
|
368
370
|
fetch_response,
|
|
@@ -380,7 +382,7 @@ class S3PrefetchReader(Readable, Seekable):
|
|
|
380
382
|
'File changed: %r, etag before: %s, after: %s' %
|
|
381
383
|
(self.name, self._content_info, response))
|
|
382
384
|
|
|
383
|
-
return
|
|
385
|
+
return response['Body']
|
|
384
386
|
|
|
385
387
|
def _submit_future(self, index: int):
|
|
386
388
|
if index < 0 or index >= self._block_stop:
|
megfile/s3_path.py
CHANGED
|
@@ -864,6 +864,9 @@ def s3_download(
|
|
|
864
864
|
:param dst_url: target fs path
|
|
865
865
|
:param callback: Called periodically during copy, and the input parameter is the data size (in bytes) of copy since the last call
|
|
866
866
|
'''
|
|
867
|
+
from megfile.fs import is_fs
|
|
868
|
+
from megfile.fs_path import FSPath
|
|
869
|
+
|
|
867
870
|
src_url = S3Path(src_url)
|
|
868
871
|
if followlinks:
|
|
869
872
|
try:
|
|
@@ -884,23 +887,31 @@ def s3_download(
|
|
|
884
887
|
'Is a directory: %r' % src_url.path_with_protocol)
|
|
885
888
|
|
|
886
889
|
dst_url = fspath(dst_url)
|
|
890
|
+
if not is_fs(dst_url):
|
|
891
|
+
raise OSError(f'dst_url is not fs path: {dst_url}')
|
|
887
892
|
if not dst_url or dst_url.endswith('/'):
|
|
888
893
|
raise S3IsADirectoryError('Is a directory: %r' % dst_url)
|
|
889
894
|
|
|
890
|
-
|
|
895
|
+
dst_path = FSPath(dst_url)
|
|
896
|
+
dst_directory = os.path.dirname(dst_path.path_without_protocol)
|
|
891
897
|
if dst_directory != '':
|
|
892
898
|
os.makedirs(dst_directory, exist_ok=True)
|
|
893
899
|
|
|
894
900
|
client = get_s3_client(profile_name=src_url._profile_name)
|
|
895
901
|
try:
|
|
896
|
-
client.download_file(
|
|
902
|
+
client.download_file(
|
|
903
|
+
src_bucket,
|
|
904
|
+
src_key,
|
|
905
|
+
dst_path.path_without_protocol,
|
|
906
|
+
Callback=callback)
|
|
897
907
|
except Exception as error:
|
|
898
908
|
error = translate_fs_error(error, dst_url)
|
|
899
909
|
error = translate_s3_error(error, src_url.path_with_protocol)
|
|
900
910
|
raise error
|
|
901
911
|
|
|
902
912
|
src_stat = src_url.stat()
|
|
903
|
-
os.utime(
|
|
913
|
+
os.utime(
|
|
914
|
+
dst_path.path_without_protocol, (src_stat.st_mtime, src_stat.st_mtime))
|
|
904
915
|
|
|
905
916
|
|
|
906
917
|
def s3_upload(
|
|
@@ -914,6 +925,13 @@ def s3_upload(
|
|
|
914
925
|
:param dst_url: target s3 path
|
|
915
926
|
:param callback: Called periodically during copy, and the input parameter is the data size (in bytes) of copy since the last call
|
|
916
927
|
'''
|
|
928
|
+
from megfile.fs import is_fs
|
|
929
|
+
from megfile.fs_path import FSPath
|
|
930
|
+
|
|
931
|
+
if not is_fs(src_url):
|
|
932
|
+
raise OSError(f'src_url is not fs path: {src_url}')
|
|
933
|
+
src_path = FSPath(src_url)
|
|
934
|
+
|
|
917
935
|
dst_bucket, dst_key = parse_s3_url(dst_url)
|
|
918
936
|
if not dst_bucket:
|
|
919
937
|
raise S3BucketNotFoundError('Empty bucket name: %r' % dst_url)
|
|
@@ -921,7 +939,7 @@ def s3_upload(
|
|
|
921
939
|
raise S3IsADirectoryError('Is a directory: %r' % dst_url)
|
|
922
940
|
|
|
923
941
|
client = get_s3_client(profile_name=S3Path(dst_url)._profile_name)
|
|
924
|
-
with open(
|
|
942
|
+
with open(src_path.path_without_protocol, 'rb') as src:
|
|
925
943
|
with raise_s3_error(dst_url):
|
|
926
944
|
client.upload_fileobj(
|
|
927
945
|
src, Bucket=dst_bucket, Key=dst_key, Callback=callback)
|
megfile/sftp_path.py
CHANGED
|
@@ -367,21 +367,24 @@ def sftp_download(
|
|
|
367
367
|
'''
|
|
368
368
|
File download
|
|
369
369
|
'''
|
|
370
|
-
from megfile.
|
|
370
|
+
from megfile.fs import is_fs
|
|
371
|
+
from megfile.fs_path import FSPath
|
|
372
|
+
|
|
371
373
|
if not is_fs(dst_url):
|
|
372
374
|
raise OSError(f'dst_url is not fs path: {dst_url}')
|
|
373
375
|
if not is_sftp(src_url):
|
|
374
376
|
raise OSError(f'src_url is not sftp path: {src_url}')
|
|
375
377
|
|
|
376
|
-
|
|
377
|
-
if followlinks and
|
|
378
|
-
|
|
379
|
-
if
|
|
378
|
+
src_path = SftpPath(src_url)
|
|
379
|
+
if followlinks and src_path.is_symlink():
|
|
380
|
+
src_path = src_path.readlink()
|
|
381
|
+
if src_path.is_dir():
|
|
380
382
|
raise IsADirectoryError('Is a directory: %r' % src_url)
|
|
381
383
|
if str(dst_url).endswith('/'):
|
|
382
384
|
raise IsADirectoryError('Is a directory: %r' % dst_url)
|
|
383
385
|
|
|
384
|
-
|
|
386
|
+
dst_path = FSPath(dst_url)
|
|
387
|
+
dst_path.parent.makedirs(exist_ok=True)
|
|
385
388
|
|
|
386
389
|
sftp_callback = None
|
|
387
390
|
if callback:
|
|
@@ -389,10 +392,12 @@ def sftp_download(
|
|
|
389
392
|
def sftp_callback(bytes_transferred: int, _total_bytes: int):
|
|
390
393
|
callback(bytes_transferred)
|
|
391
394
|
|
|
392
|
-
|
|
395
|
+
src_path._client.get(
|
|
396
|
+
src_path._real_path,
|
|
397
|
+
dst_path.path_without_protocol,
|
|
398
|
+
callback=sftp_callback)
|
|
393
399
|
|
|
394
|
-
src_stat =
|
|
395
|
-
dst_path = FSPath(dst_url)
|
|
400
|
+
src_stat = src_path.stat()
|
|
396
401
|
dst_path.utime(src_stat.st_atime, src_stat.st_mtime)
|
|
397
402
|
dst_path.chmod(src_stat.st_mode)
|
|
398
403
|
|
|
@@ -405,7 +410,9 @@ def sftp_upload(
|
|
|
405
410
|
'''
|
|
406
411
|
File upload
|
|
407
412
|
'''
|
|
408
|
-
from megfile.fs import
|
|
413
|
+
from megfile.fs import is_fs
|
|
414
|
+
from megfile.fs_path import FSPath
|
|
415
|
+
|
|
409
416
|
if not is_fs(src_url):
|
|
410
417
|
raise OSError(f'src_url is not fs path: {src_url}')
|
|
411
418
|
if not is_sftp(dst_url):
|
|
@@ -418,8 +425,9 @@ def sftp_upload(
|
|
|
418
425
|
if str(dst_url).endswith('/'):
|
|
419
426
|
raise IsADirectoryError('Is a directory: %r' % dst_url)
|
|
420
427
|
|
|
421
|
-
|
|
422
|
-
dst_url
|
|
428
|
+
src_path = FSPath(src_url)
|
|
429
|
+
dst_path = SftpPath(dst_url)
|
|
430
|
+
dst_path.parent.makedirs(exist_ok=True)
|
|
423
431
|
|
|
424
432
|
sftp_callback = None
|
|
425
433
|
if callback:
|
|
@@ -427,11 +435,14 @@ def sftp_upload(
|
|
|
427
435
|
def sftp_callback(bytes_transferred: int, _total_bytes: int):
|
|
428
436
|
callback(bytes_transferred)
|
|
429
437
|
|
|
430
|
-
|
|
438
|
+
dst_path._client.put(
|
|
439
|
+
src_path.path_without_protocol,
|
|
440
|
+
dst_path._real_path,
|
|
441
|
+
callback=sftp_callback)
|
|
431
442
|
|
|
432
|
-
src_stat =
|
|
433
|
-
|
|
434
|
-
|
|
443
|
+
src_stat = src_path.stat()
|
|
444
|
+
dst_path.utime(src_stat.st_atime, src_stat.st_mtime)
|
|
445
|
+
dst_path.chmod(src_stat.st_mode)
|
|
435
446
|
|
|
436
447
|
|
|
437
448
|
def sftp_path_join(path: PathLike, *other_paths: PathLike) -> str:
|
megfile/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = "2.2.0"
|
|
1
|
+
VERSION = "2.2.0.post1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
megfile/__init__.py,sha256=Qsi3XNP_0XYoSol-1AGutZqo0rfBnzaiZ-HVXll4fB0,5721
|
|
2
|
-
megfile/cli.py,sha256=
|
|
3
|
-
megfile/errors.py,sha256=
|
|
2
|
+
megfile/cli.py,sha256=E3NoSZ8D-k3OCRXPDysFkjeHRunZXw4QvqjP5QNsgUg,12806
|
|
3
|
+
megfile/errors.py,sha256=y0PJ4lzkm-uqgVD1EqakmN0IHBMt1CCzDbdbq84sVb4,11491
|
|
4
4
|
megfile/fs.py,sha256=sjkm_LsvNCw8hj9Ee-1HSNzvg7bRHTPem8KTDDBQlCw,11621
|
|
5
5
|
megfile/fs_path.py,sha256=Lz-u8XL2RMViHl_39yapAwX5XSE_ZpQsuhAvVve6rk8,38532
|
|
6
6
|
megfile/http.py,sha256=Juz95GscschvmElieLIWqO2A4BrqJnrtTWTa9uzNN_4,2477
|
|
@@ -8,14 +8,14 @@ megfile/http_path.py,sha256=XtpbYHdtHZysjkz6Xdr4fe8E6hlsV4iLNoIZaBk-_P4,5360
|
|
|
8
8
|
megfile/interfaces.py,sha256=h3tWE8hVt5S-HopaMAX6lunPJ97vzhv6jH_2HubcDNc,6219
|
|
9
9
|
megfile/pathlike.py,sha256=52e6POtMfUCC3Hb9XNwBLXM3Gkz3aGP8H8AagGKlDSg,29307
|
|
10
10
|
megfile/s3.py,sha256=6d9bBVkVdXIvmJLfpOgJkK4nVAsLR3lirrB6x1-P2y8,12437
|
|
11
|
-
megfile/s3_path.py,sha256
|
|
11
|
+
megfile/s3_path.py,sha256=-odQ7rg38khf1Bc8webKBZewIfKIV5I1a-qsdshLLzA,85287
|
|
12
12
|
megfile/sftp.py,sha256=qzfgI-MGzNsr7adUQaiVKS7zRHGuK-Hs6o45wNIAcww,11943
|
|
13
|
-
megfile/sftp_path.py,sha256=
|
|
13
|
+
megfile/sftp_path.py,sha256=lbestqN_FXwIJbqFeHXLkq306B2zqVILFda4peKOQwY,47288
|
|
14
14
|
megfile/smart.py,sha256=xjRRujYAPzXlrYxV7ZCAPXl0biUNn4730ATKc_tzIzE,32694
|
|
15
15
|
megfile/smart_path.py,sha256=Rwb1McXsshi9-F6miTRqE6j8FO2j1edjmSxZF32YZ6E,6708
|
|
16
16
|
megfile/stdio.py,sha256=qmi1c7VTll6Y6ya9MCd-dSKffocX2GafA-YUncZRU1Y,559
|
|
17
17
|
megfile/stdio_path.py,sha256=ULMzGOj7SBMn3c7fYVSDepT_1nEUiVetc-xRt2pR5o4,2682
|
|
18
|
-
megfile/version.py,sha256=
|
|
18
|
+
megfile/version.py,sha256=wEKo6RBa-JfaOX7tcmNU28H0l1ZzziU5CEqvjD8Y1AU,25
|
|
19
19
|
megfile/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
20
|
megfile/lib/combine_reader.py,sha256=XFSqEY5A5X5Uf7eQ6AXAzrvNteESSXvKNVPktGjo3KY,4546
|
|
21
21
|
megfile/lib/compare.py,sha256=yG2fZve_gMg32rQVCdwixBdqgYRsjn-24TqhALQaOrA,2233
|
|
@@ -29,17 +29,17 @@ megfile/lib/s3_cached_handler.py,sha256=e4KamTLMIPKa96yp7HGF05wDl2Yfoizz9pBrz-uA
|
|
|
29
29
|
megfile/lib/s3_limited_seekable_writer.py,sha256=NSBh5cZCCtwZM0DTwfPkpOA_h0NXd9-6qjasOby5zxc,6037
|
|
30
30
|
megfile/lib/s3_memory_handler.py,sha256=jLBA5HVuI-UBPYMYN-B8iX_VGr8bC9brAqY-KbEGrtw,3725
|
|
31
31
|
megfile/lib/s3_pipe_handler.py,sha256=38x8oPrxlXVWqMgDOqScPj0Pt2w2cQFSNoTK27EtBSw,3384
|
|
32
|
-
megfile/lib/s3_prefetch_reader.py,sha256=
|
|
32
|
+
megfile/lib/s3_prefetch_reader.py,sha256=uffgYsNy7sfiZdoZdY67LYiQiPagtohl4BeQ6jSTwEM,15113
|
|
33
33
|
megfile/lib/s3_share_cache_reader.py,sha256=QyZvzVpTswgiXv-E8QhV_jFdQjCBxVcgbgybXo6d1cM,3771
|
|
34
34
|
megfile/lib/shadow_handler.py,sha256=IbFyTw107t-yWH0cGrDjAJX-CS3xeEr77_PTGsnSgk4,2683
|
|
35
35
|
megfile/lib/stdio_handler.py,sha256=QDWtcZxz-hzi-rqQUiSlR3NrihX1fjK_Rj9T2mdTFEg,2044
|
|
36
36
|
megfile/lib/url.py,sha256=VbQLjo0s4AaV0iSk66BcjI68aUTcN9zBZ5x6-cM4Qvs,103
|
|
37
37
|
megfile/utils/__init__.py,sha256=DEVSwUQ1-1rkHBIuXBxgEYiepq8W25JIWYQrC1gcFrc,9005
|
|
38
38
|
megfile/utils/mutex.py,sha256=-2KH3bNovKRd9zvsXq9n3bWM7rQdoG9hO7tUPxVG_Po,2538
|
|
39
|
-
megfile-2.2.0.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
40
|
-
megfile-2.2.0.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
|
|
41
|
-
megfile-2.2.0.dist-info/METADATA,sha256=
|
|
42
|
-
megfile-2.2.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
43
|
-
megfile-2.2.0.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
|
|
44
|
-
megfile-2.2.0.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
|
|
45
|
-
megfile-2.2.0.dist-info/RECORD,,
|
|
39
|
+
megfile-2.2.0.post1.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
40
|
+
megfile-2.2.0.post1.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
|
|
41
|
+
megfile-2.2.0.post1.dist-info/METADATA,sha256=WUowRbsO-dMPhEJYA1YQY0DNYRGc2jw6kdYRYQLnoBQ,10601
|
|
42
|
+
megfile-2.2.0.post1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
43
|
+
megfile-2.2.0.post1.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
|
|
44
|
+
megfile-2.2.0.post1.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
|
|
45
|
+
megfile-2.2.0.post1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|