megfile 2.2.5.post1__py3-none-any.whl → 2.2.6a1__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
@@ -4,13 +4,14 @@ import shutil
4
4
  import sys
5
5
  import time
6
6
  from concurrent.futures import ThreadPoolExecutor
7
+ from functools import partial
7
8
 
8
9
  import click
9
10
  from tqdm import tqdm
10
11
 
11
12
  from megfile.interfaces import FileEntry
12
13
  from megfile.lib.glob import get_non_glob_dir, has_magic
13
- from megfile.smart import smart_copy, smart_getmd5, smart_getmtime, smart_getsize, smart_glob, smart_glob_stat, smart_isdir, smart_isfile, smart_makedirs, smart_move, smart_open, smart_path_join, smart_remove, smart_rename, smart_scan_stat, smart_scandir, smart_stat, smart_sync, smart_sync_with_progress, smart_touch, smart_unlink
14
+ from megfile.smart import _smart_sync_single_file, smart_copy, smart_getmd5, smart_getmtime, smart_getsize, smart_glob_stat, smart_isdir, smart_isfile, smart_makedirs, smart_move, smart_open, smart_path_join, smart_remove, smart_rename, smart_scan_stat, smart_scandir, smart_stat, smart_sync, smart_sync_with_progress, smart_touch, smart_unlink
14
15
  from megfile.smart_path import SmartPath
15
16
  from megfile.utils import get_human_size
16
17
  from megfile.version import VERSION
@@ -32,34 +33,36 @@ def safe_cli(): # pragma: no cover
32
33
  click.echo(f"\n[{type(e).__name__}] {e}", err=True)
33
34
 
34
35
 
35
- def get_echo_path(file_stat, base_path: str = ""):
36
+ def get_echo_path(file_stat, base_path: str = "", full_path: bool = False):
36
37
  if base_path == file_stat.path:
37
38
  path = file_stat.name
39
+ elif full_path:
40
+ path = file_stat.path
38
41
  else:
39
42
  path = os.path.relpath(file_stat.path, start=base_path)
40
43
  return path
41
44
 
42
45
 
43
- def simple_echo(file_stat, base_path: str = ""):
44
- click.echo(get_echo_path(file_stat, base_path))
46
+ def simple_echo(file_stat, base_path: str = "", full_path: bool = False):
47
+ click.echo(get_echo_path(file_stat, base_path, full_path))
45
48
 
46
49
 
47
- def long_echo(file_stat, base_path: str = ""):
50
+ def long_echo(file_stat, base_path: str = "", full_path: bool = False):
48
51
  click.echo(
49
52
  '%12d %s %s' % (
50
53
  file_stat.stat.size,
51
54
  time.strftime(
52
55
  "%Y-%m-%d %H:%M:%S", time.localtime(file_stat.stat.mtime)),
53
- get_echo_path(file_stat, base_path)))
56
+ get_echo_path(file_stat, base_path, full_path)))
54
57
 
55
58
 
56
- def human_echo(file_stat, base_path: str = ""):
59
+ def human_echo(file_stat, base_path: str = "", full_path: bool = False):
57
60
  click.echo(
58
61
  '%10s %s %s' % (
59
62
  get_human_size(file_stat.stat.size),
60
63
  time.strftime(
61
64
  "%Y-%m-%d %H:%M:%S", time.localtime(file_stat.stat.mtime)),
62
- get_echo_path(file_stat, base_path)))
65
+ get_echo_path(file_stat, base_path, full_path)))
63
66
 
64
67
 
65
68
  def smart_list_stat(path):
@@ -91,9 +94,11 @@ def smart_list_stat(path):
91
94
  help='Displays file sizes in human readable format.')
92
95
  def ls(path: str, long: bool, recursive: bool, human_readable: bool):
93
96
  base_path = path
97
+ full_path = False
94
98
  if has_magic(path):
95
99
  scan_func = smart_glob_stat
96
100
  base_path = get_non_glob_dir(path)
101
+ full_path = True
97
102
  elif recursive:
98
103
  scan_func = smart_scan_stat
99
104
  else:
@@ -107,7 +112,7 @@ def ls(path: str, long: bool, recursive: bool, human_readable: bool):
107
112
  echo_func = simple_echo
108
113
 
109
114
  for file_stat in scan_func(path):
110
- echo_func(file_stat, base_path)
115
+ echo_func(file_stat, base_path, full_path=full_path)
111
116
 
112
117
 
113
118
  @cli.command(
@@ -264,65 +269,81 @@ def rm(path: str, recursive: bool):
264
269
  '--force',
265
270
  is_flag=True,
266
271
  help='Copy files forcely, ignore same files.')
272
+ @click.option('-q', '--quiet', is_flag=True, help='Not show any progress log.')
267
273
  def sync(
268
274
  src_path: str, dst_path: str, progress_bar: bool, worker: int,
269
- force: bool):
275
+ force: bool, quiet: bool):
270
276
  with ThreadPoolExecutor(max_workers=worker) as executor:
271
277
  if has_magic(src_path):
272
- root_dir = get_non_glob_dir(src_path)
273
- path_stats = []
274
- for dir_or_file in smart_glob(src_path, recursive=True,
275
- missing_ok=True):
276
- path_stats.extend(list(smart_scan_stat(dir_or_file)))
278
+ src_root_path = get_non_glob_dir(src_path)
279
+
280
+ def scan_func(path):
281
+ for glob_file_entry in smart_glob_stat(path):
282
+ if glob_file_entry.is_file():
283
+ yield glob_file_entry
284
+ else:
285
+ for file_entry in smart_scan_stat(glob_file_entry.path,
286
+ followlinks=True):
287
+ yield file_entry
288
+ else:
289
+ src_root_path = src_path
290
+ scan_func = partial(smart_scan_stat, followlinks=True)
291
+
292
+ if progress_bar and not quiet:
293
+ print('building progress bar', end='\r')
294
+ file_entries = []
295
+ total_count = total_size = 0
296
+ for total_count, file_entry in enumerate(scan_func(src_path),
297
+ start=1):
298
+ if total_count > 1024 * 128:
299
+ file_entries = []
300
+ else:
301
+ file_entries.append(file_entry)
302
+ total_size += file_entry.stat.size
303
+ print(
304
+ f'building progress bar, find {total_count} files',
305
+ end='\r')
306
+
307
+ if not file_entries:
308
+ file_entries = scan_func(src_path)
309
+ else:
310
+ total_count = total_size = None
311
+ file_entries = scan_func(src_path)
277
312
 
278
- if progress_bar:
279
- tbar = tqdm(total=len(path_stats), ascii=True)
280
- sbar = tqdm(
281
- unit='B', ascii=True, unit_scale=True, unit_divisor=1024)
313
+ if quiet:
314
+ callback = callback_after_copy_file = None
315
+ else:
316
+ tbar = tqdm(total=total_count, ascii=True)
317
+ sbar = tqdm(
318
+ unit='B',
319
+ ascii=True,
320
+ unit_scale=True,
321
+ unit_divisor=1024,
322
+ total=total_size)
282
323
 
283
- def callback(_filename: str, length: int):
284
- sbar.update(length)
324
+ def callback(_filename: str, length: int):
325
+ sbar.update(length)
285
326
 
286
- def callback_after_copy_file(src_file_path, dst_file_path):
287
- tbar.update(1)
327
+ def callback_after_copy_file(src_file_path, dst_file_path):
328
+ tbar.update(1)
288
329
 
289
- smart_sync(
290
- root_dir,
291
- dst_path,
330
+ for file_entry in file_entries:
331
+ executor.submit(
332
+ _smart_sync_single_file,
333
+ dict(
334
+ src_root_path=src_root_path,
335
+ dst_root_path=dst_path,
336
+ src_file_path=file_entry.path,
292
337
  callback=callback,
293
- callback_after_copy_file=callback_after_copy_file,
294
- src_file_stats=path_stats,
295
- map_func=executor.map,
296
- force=force,
297
338
  followlinks=True,
298
- )
299
-
300
- tbar.close()
301
- sbar.close()
302
- else:
303
- smart_sync(
304
- root_dir,
305
- dst_path,
306
- src_file_stats=path_stats,
307
- map_func=executor.map,
339
+ callback_after_copy_file=callback_after_copy_file,
308
340
  force=force,
309
- followlinks=True,
310
- )
311
- else:
312
- if progress_bar:
313
- smart_sync_with_progress(
314
- src_path,
315
- dst_path,
316
- followlinks=True,
317
- map_func=executor.map,
318
- force=force)
319
- else:
320
- smart_sync(
321
- src_path,
322
- dst_path,
323
- followlinks=True,
324
- map_func=executor.map,
325
- force=force)
341
+ ))
342
+ if not quiet:
343
+ tbar.close()
344
+ if progress_bar:
345
+ sbar.update(sbar.total - sbar.n)
346
+ sbar.close()
326
347
 
327
348
 
328
349
  @cli.command(short_help="Make the path if it doesn't already exist.")
megfile/errors.py CHANGED
@@ -110,7 +110,7 @@ def s3_should_retry(error: Exception) -> bool:
110
110
  if isinstance(error, botocore.exceptions.ClientError):
111
111
  return client_error_code(error) in (
112
112
  '500', '501', '502', '503', 'InternalError', 'ServiceUnavailable',
113
- 'SlowDown')
113
+ 'SlowDown', 'ContextCanceled')
114
114
  return False
115
115
 
116
116
 
@@ -52,11 +52,13 @@ class S3BufferedWriter(Writable):
52
52
  block_size: int = DEFAULT_BLOCK_SIZE,
53
53
  max_block_size: int = DEFAULT_MAX_BLOCK_SIZE,
54
54
  max_buffer_size: int = DEFAULT_MAX_BUFFER_SIZE,
55
- max_workers: Optional[int] = None):
55
+ max_workers: Optional[int] = None,
56
+ profile_name: Optional[str] = None):
56
57
 
57
58
  self._bucket = bucket
58
59
  self._key = key
59
60
  self._client = s3_client
61
+ self._profile_name = profile_name
60
62
 
61
63
  self._block_size = block_size
62
64
  self._max_block_size = max_block_size
@@ -86,7 +88,9 @@ class S3BufferedWriter(Writable):
86
88
 
87
89
  @property
88
90
  def name(self) -> str:
89
- return 's3://%s/%s' % (self._bucket, self._key)
91
+ return 's3%s://%s/%s' % (
92
+ f"+{self._profile_name}" if self._profile_name else "",
93
+ self._bucket, self._key)
90
94
 
91
95
  @property
92
96
  def mode(self) -> str:
@@ -17,7 +17,8 @@ class S3CachedHandler(S3MemoryHandler):
17
17
  *,
18
18
  s3_client,
19
19
  cache_path: Optional[str] = None,
20
- remove_cache_when_open: bool = True):
20
+ remove_cache_when_open: bool = True,
21
+ profile_name: Optional[str] = None):
21
22
 
22
23
  assert mode in ('rb', 'wb', 'ab', 'rb+', 'wb+', 'ab+')
23
24
 
@@ -25,6 +26,7 @@ class S3CachedHandler(S3MemoryHandler):
25
26
  self._key = key
26
27
  self._mode = mode
27
28
  self._client = s3_client
29
+ self._profile_name = profile_name
28
30
 
29
31
  if cache_path is None:
30
32
  cache_path = generate_cache_path(self.name)
@@ -29,7 +29,8 @@ class S3LimitedSeekableWriter(Seekable, S3BufferedWriter):
29
29
  tail_block_size: Optional[int] = None,
30
30
  max_block_size: int = DEFAULT_MAX_BLOCK_SIZE,
31
31
  max_buffer_size: int = DEFAULT_MAX_BUFFER_SIZE,
32
- max_workers: Optional[int] = None):
32
+ max_workers: Optional[int] = None,
33
+ profile_name: Optional[str] = None):
33
34
 
34
35
  super().__init__(
35
36
  bucket,
@@ -38,7 +39,8 @@ class S3LimitedSeekableWriter(Seekable, S3BufferedWriter):
38
39
  block_size=block_size,
39
40
  max_block_size=max_block_size,
40
41
  max_buffer_size=max_buffer_size,
41
- max_workers=max_workers)
42
+ max_workers=max_workers,
43
+ profile_name=profile_name)
42
44
 
43
45
  self._head_block_size = head_block_size or block_size
44
46
  self._tail_block_size = tail_block_size or block_size
@@ -8,7 +8,14 @@ from megfile.interfaces import Readable, Seekable, Writable
8
8
 
9
9
  class S3MemoryHandler(Readable, Seekable, Writable):
10
10
 
11
- def __init__(self, bucket: str, key: str, mode: str, *, s3_client):
11
+ def __init__(
12
+ self,
13
+ bucket: str,
14
+ key: str,
15
+ mode: str,
16
+ *,
17
+ s3_client,
18
+ profile_name: Optional[str] = None):
12
19
 
13
20
  assert mode in ('rb', 'wb', 'ab', 'rb+', 'wb+', 'ab+')
14
21
 
@@ -16,13 +23,16 @@ class S3MemoryHandler(Readable, Seekable, Writable):
16
23
  self._key = key
17
24
  self._mode = mode
18
25
  self._client = s3_client
26
+ self._profile_name = profile_name
19
27
 
20
28
  self._fileobj = BytesIO()
21
29
  self._download_fileobj()
22
30
 
23
31
  @property
24
32
  def name(self) -> str:
25
- return 's3://%s/%s' % (self._bucket, self._key)
33
+ return 's3%s://%s/%s' % (
34
+ f"+{self._profile_name}" if self._profile_name else "",
35
+ self._bucket, self._key)
26
36
 
27
37
  @property
28
38
  def mode(self) -> str:
@@ -33,7 +33,8 @@ class S3PipeHandler(Readable, Writable):
33
33
  mode: str,
34
34
  *,
35
35
  s3_client,
36
- join_thread: bool = True):
36
+ join_thread: bool = True,
37
+ profile_name: Optional[str] = None):
37
38
 
38
39
  assert mode in ('rb', 'wb')
39
40
 
@@ -43,6 +44,7 @@ class S3PipeHandler(Readable, Writable):
43
44
  self._client = s3_client
44
45
  self._join_thread = join_thread
45
46
  self._offset = 0
47
+ self._profile_name = profile_name
46
48
 
47
49
  self._exc = None
48
50
  self._pipe = os.pipe()
@@ -59,7 +61,9 @@ class S3PipeHandler(Readable, Writable):
59
61
 
60
62
  @property
61
63
  def name(self) -> str:
62
- return 's3://%s/%s' % (self._bucket, self._key)
64
+ return 's3%s://%s/%s' % (
65
+ f"+{self._profile_name}" if self._profile_name else "",
66
+ self._bucket, self._key)
63
67
 
64
68
  @property
65
69
  def mode(self) -> str:
@@ -34,11 +34,13 @@ class S3PrefetchReader(BasePrefetchReader):
34
34
  block_capacity: int = DEFAULT_BLOCK_CAPACITY,
35
35
  block_forward: Optional[int] = None,
36
36
  max_retries: int = 10,
37
- max_workers: Optional[int] = None):
37
+ max_workers: Optional[int] = None,
38
+ profile_name: Optional[str] = None):
38
39
 
39
40
  self._bucket = bucket
40
41
  self._key = key
41
42
  self._client = s3_client
43
+ self._profile_name = profile_name
42
44
 
43
45
  super().__init__(
44
46
  block_size=block_size,
@@ -68,7 +70,9 @@ class S3PrefetchReader(BasePrefetchReader):
68
70
 
69
71
  @property
70
72
  def name(self) -> str:
71
- return 's3://%s/%s' % (self._bucket, self._key)
73
+ return 's3%s://%s/%s' % (
74
+ f"+{self._profile_name}" if self._profile_name else "",
75
+ self._bucket, self._key)
72
76
 
73
77
  def _fetch_response(
74
78
  self, start: Optional[int] = None,
@@ -34,7 +34,8 @@ class S3ShareCacheReader(S3PrefetchReader):
34
34
  block_forward: Optional[int] = None,
35
35
  max_retries: int = 10,
36
36
  cache_key: str = 'lru',
37
- max_workers: Optional[int] = None):
37
+ max_workers: Optional[int] = None,
38
+ profile_name: Optional[str] = None):
38
39
 
39
40
  self._cache_key = cache_key
40
41
 
@@ -47,6 +48,7 @@ class S3ShareCacheReader(S3PrefetchReader):
47
48
  block_forward=block_forward,
48
49
  max_retries=max_retries,
49
50
  max_workers=max_workers,
51
+ profile_name=profile_name,
50
52
  )
51
53
 
52
54
  def _get_block_forward(
megfile/s3_path.py CHANGED
@@ -193,6 +193,13 @@ def get_s3_client(
193
193
 
194
194
  :returns: S3 client
195
195
  '''
196
+ if cache_key is not None:
197
+ return thread_local(
198
+ f"{cache_key}:{profile_name}",
199
+ get_s3_client,
200
+ config=config,
201
+ profile_name=profile_name)
202
+
196
203
  if config:
197
204
  config = config.merge(botocore.config.Config(connect_timeout=5))
198
205
  else:
@@ -207,10 +214,6 @@ def get_s3_client(
207
214
  config = config.merge(
208
215
  botocore.config.Config(s3={'addressing_style': addressing_style}))
209
216
 
210
- if cache_key is not None:
211
- return thread_local(
212
- cache_key, get_s3_client, config=config, profile_name=profile_name)
213
-
214
217
  access_key, secret_key = get_access_token(profile_name)
215
218
  try:
216
219
  session = get_s3_session(profile_name=profile_name)
@@ -595,7 +598,8 @@ def s3_prefetch_open(
595
598
  s3_client=client,
596
599
  max_retries=max_retries,
597
600
  max_workers=max_concurrency,
598
- block_size=max_block_size)
601
+ block_size=max_block_size,
602
+ profile_name=s3_url._profile_name)
599
603
 
600
604
 
601
605
  @_s3_binary_mode
@@ -646,7 +650,8 @@ def s3_share_cache_open(
646
650
  s3_client=client,
647
651
  max_retries=max_retries,
648
652
  max_workers=max_concurrency,
649
- block_size=max_block_size)
653
+ block_size=max_block_size,
654
+ profile_name=s3_url._profile_name)
650
655
 
651
656
 
652
657
  @_s3_binary_mode
@@ -693,7 +698,12 @@ def s3_pipe_open(
693
698
  cache_key='s3_filelike_client',
694
699
  profile_name=s3_url._profile_name)
695
700
  return S3PipeHandler(
696
- bucket, key, mode, s3_client=client, join_thread=join_thread)
701
+ bucket,
702
+ key,
703
+ mode,
704
+ s3_client=client,
705
+ join_thread=join_thread,
706
+ profile_name=s3_url._profile_name)
697
707
 
698
708
 
699
709
  @_s3_binary_mode
@@ -734,7 +744,12 @@ def s3_cached_open(
734
744
  cache_key='s3_filelike_client',
735
745
  profile_name=s3_url._profile_name)
736
746
  return S3CachedHandler(
737
- bucket, key, mode, s3_client=client, cache_path=cache_path)
747
+ bucket,
748
+ key,
749
+ mode,
750
+ s3_client=client,
751
+ cache_path=cache_path,
752
+ profile_name=s3_url._profile_name)
738
753
 
739
754
 
740
755
  @_s3_binary_mode
@@ -789,9 +804,19 @@ def s3_buffered_open(
789
804
 
790
805
  if 'a' in mode or '+' in mode:
791
806
  if cache_path is None:
792
- return S3MemoryHandler(bucket, key, mode, s3_client=client)
807
+ return S3MemoryHandler(
808
+ bucket,
809
+ key,
810
+ mode,
811
+ s3_client=client,
812
+ profile_name=s3_url._profile_name)
793
813
  return S3CachedHandler(
794
- bucket, key, mode, s3_client=client, cache_path=cache_path)
814
+ bucket,
815
+ key,
816
+ mode,
817
+ s3_client=client,
818
+ cache_path=cache_path,
819
+ profile_name=s3_url._profile_name)
795
820
 
796
821
  if mode == 'rb':
797
822
  # A rough conversion algorithm to align 2 types of Reader / Writer parameters
@@ -810,7 +835,8 @@ def s3_buffered_open(
810
835
  max_retries=max_retries,
811
836
  max_workers=max_concurrency,
812
837
  block_size=block_size,
813
- block_forward=block_forward)
838
+ block_forward=block_forward,
839
+ profile_name=s3_url._profile_name)
814
840
  else:
815
841
  reader = S3PrefetchReader(
816
842
  bucket,
@@ -820,7 +846,8 @@ def s3_buffered_open(
820
846
  max_workers=max_concurrency,
821
847
  block_capacity=block_capacity,
822
848
  block_forward=block_forward,
823
- block_size=block_size)
849
+ block_size=block_size,
850
+ profile_name=s3_url._profile_name)
824
851
  if buffered:
825
852
  reader = io.BufferedReader(reader) # pytype: disable=wrong-arg-types
826
853
  return reader
@@ -832,7 +859,8 @@ def s3_buffered_open(
832
859
  s3_client=client,
833
860
  max_workers=max_concurrency,
834
861
  max_buffer_size=max_buffer_size,
835
- block_size=block_size)
862
+ block_size=block_size,
863
+ profile_name=s3_url._profile_name)
836
864
  else:
837
865
  writer = S3BufferedWriter(
838
866
  bucket,
@@ -840,7 +868,8 @@ def s3_buffered_open(
840
868
  s3_client=client,
841
869
  max_workers=max_concurrency,
842
870
  max_buffer_size=max_buffer_size,
843
- block_size=block_size)
871
+ block_size=block_size,
872
+ profile_name=s3_url._profile_name)
844
873
  if buffered:
845
874
  writer = io.BufferedWriter(writer) # pytype: disable=wrong-arg-types
846
875
  return writer
@@ -877,7 +906,8 @@ def s3_memory_open(
877
906
  config=config,
878
907
  cache_key='s3_filelike_client',
879
908
  profile_name=s3_url._profile_name)
880
- return S3MemoryHandler(bucket, key, mode, s3_client=client)
909
+ return S3MemoryHandler(
910
+ bucket, key, mode, s3_client=client, profile_name=s3_url._profile_name)
881
911
 
882
912
 
883
913
  s3_open = s3_buffered_open
megfile/sftp_path.py CHANGED
@@ -1,7 +1,9 @@
1
1
  import atexit
2
+ import fcntl
2
3
  import hashlib
3
4
  import io
4
5
  import os
6
+ import random
5
7
  import shlex
6
8
  import socket
7
9
  import subprocess
@@ -43,6 +45,7 @@ SFTP_PASSWORD = "SFTP_PASSWORD"
43
45
  SFTP_PRIVATE_KEY_PATH = "SFTP_PRIVATE_KEY_PATH"
44
46
  SFTP_PRIVATE_KEY_TYPE = "SFTP_PRIVATE_KEY_TYPE"
45
47
  SFTP_PRIVATE_KEY_PASSWORD = "SFTP_PRIVATE_KEY_PASSWORD"
48
+ SFTP_MAX_UNAUTH_CONN = "SFTP_MAX_UNAUTH_CONN"
46
49
  MAX_RETRIES = 10
47
50
  DEFAULT_SSH_CONNECT_TIMEOUT = 5
48
51
  DEFAULT_SSH_KEEPALIVE_INTERVAL = 15
@@ -194,6 +197,20 @@ def _get_ssh_client(
194
197
 
195
198
  ssh_client = paramiko.SSHClient()
196
199
  ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
200
+ max_unauth_connections = int(os.getenv(SFTP_MAX_UNAUTH_CONN, 10))
201
+ try:
202
+ fd = os.open(
203
+ os.path.join(
204
+ '/tmp',
205
+ f'megfile-sftp-{hostname}-{random.randint(1, max_unauth_connections)}'
206
+ ), os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
207
+ except Exception:
208
+ _logger.warning(
209
+ "Can't create file lock in '/tmp', please control the SFTP concurrency count by yourself."
210
+ )
211
+ fd = None
212
+ if fd:
213
+ fcntl.flock(fd, fcntl.LOCK_EX)
197
214
  ssh_client.connect(
198
215
  hostname=hostname,
199
216
  username=username,
@@ -203,6 +220,9 @@ def _get_ssh_client(
203
220
  auth_timeout=DEFAULT_SSH_CONNECT_TIMEOUT,
204
221
  banner_timeout=DEFAULT_SSH_CONNECT_TIMEOUT,
205
222
  )
223
+ if fd:
224
+ fcntl.flock(fd, fcntl.LOCK_UN)
225
+ os.close(fd)
206
226
  atexit.register(ssh_client.close)
207
227
  return ssh_client
208
228
 
megfile/version.py CHANGED
@@ -1 +1 @@
1
- VERSION = "2.2.5.post1"
1
+ VERSION = "2.2.6a1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: megfile
3
- Version: 2.2.5.post1
3
+ Version: 2.2.6a1
4
4
  Summary: Megvii file operation library
5
5
  Home-page: https://github.com/megvii-research/megfile
6
6
  Author: megvii
@@ -1,6 +1,6 @@
1
1
  megfile/__init__.py,sha256=Qsi3XNP_0XYoSol-1AGutZqo0rfBnzaiZ-HVXll4fB0,5721
2
- megfile/cli.py,sha256=Elv8Dvyvy0l8tXuzuw8GAfhUuZgnbxsndgIKQU98ltc,13701
3
- megfile/errors.py,sha256=NBpcxnsy5bvhlaTol8eIB8dwC54y-XqAGroS5wjk9AY,11934
2
+ megfile/cli.py,sha256=m6nqGc_vjA68SMv0NsqM-R5RpnZNczA4JI4Gt_mcFPw,14743
3
+ megfile/errors.py,sha256=IDqfdz0WjCwvV1Zp8N9iKFE8Y0nrYBH6c7_4EW_CJaM,11953
4
4
  megfile/fs.py,sha256=LtrzQsyZgogTJeoRFz4L52gxx0jByzRBLkpWYpvkp5I,11819
5
5
  megfile/fs_path.py,sha256=JkY8qGIIboK5MK2rSagYEvnu5FTzmk9OHXIhTO7BjeY,38767
6
6
  megfile/http.py,sha256=a3oAuARSSaIU8VMx86Mui0N5Vh-EI0AoHnwxRU5DSMU,2032
@@ -8,14 +8,14 @@ megfile/http_path.py,sha256=9X9klm6CtEfu4V0_LUWtSXC8JRYiNjVAJjdzEBfxUa8,9272
8
8
  megfile/interfaces.py,sha256=h3tWE8hVt5S-HopaMAX6lunPJ97vzhv6jH_2HubcDNc,6219
9
9
  megfile/pathlike.py,sha256=WpP8zWSOAcAfYrD65hZS08UEi4_iCoEMs2xvfFMwZvY,29264
10
10
  megfile/s3.py,sha256=7XZSWjcSY-hoLhLH9dtfyRpokfYH9raTO_Mf69RjpEs,12560
11
- megfile/s3_path.py,sha256=QHgfkOeXjT2kEM6PrYIH8uvA-3k-WSH_LdXaaMd7LeQ,87666
11
+ megfile/s3_path.py,sha256=1bxhf8-Lg29oFB6BFbIQGDvKvSIE7ZS-YORHbe6kOiM,88409
12
12
  megfile/sftp.py,sha256=CZYv1WKL0d_vuJ5aPgMhm0W8uskzaO5zbYGhGwt_mQs,12771
13
- megfile/sftp_path.py,sha256=P3NIL-4Wd143Rnnh2c3Ai2r2nc_EGoVNg4hpoHCoVvA,49865
13
+ megfile/sftp_path.py,sha256=DG-X79bcPc1hikZ_PNha3K_ber8bqjx-KnW3jZG8iCw,50529
14
14
  megfile/smart.py,sha256=JH5zed90eQchS8GNQ7mbXvif-pNKjPjvnadMazKfQMs,33278
15
15
  megfile/smart_path.py,sha256=Y0UFh4J2ccydRY2W-wX2ubaf9zzJx1M2nf-VLBGe4mk,6749
16
16
  megfile/stdio.py,sha256=yRhlfUA2DHi3bq-9cXsSlbLCnHvS_zvglO2IYYyPsGc,707
17
17
  megfile/stdio_path.py,sha256=eQulTXUwHvUKA-5PKCGfVNiEPkJhG9YtVhtU58OcmoM,2873
18
- megfile/version.py,sha256=koBbHXdAjXmq3rwimA394uqdF7MP1eE6yjkJRUom4DI,25
18
+ megfile/version.py,sha256=s1UlNdCKmZ0EggJzQ2Wu1Nz0xneCzoLAvSAoUlQHunY,21
19
19
  megfile/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  megfile/lib/base_prefetch_reader.py,sha256=SjrBffHVgvJnYtr8HNqiOozP9OJRYS37Eu1KQcZu1Z8,13221
21
21
  megfile/lib/combine_reader.py,sha256=XFSqEY5A5X5Uf7eQ6AXAzrvNteESSXvKNVPktGjo3KY,4546
@@ -26,22 +26,22 @@ megfile/lib/glob.py,sha256=7i9dIput9rI9JIPyTZX-JDmFS7IP_THlX1k-35foAfw,9732
26
26
  megfile/lib/http_prefetch_reader.py,sha256=YDtQXRX-yxyaFzqI_CL3X73-Idkdz1aPIDL29uY77zw,3326
27
27
  megfile/lib/joinpath.py,sha256=D4Px6-lnDDpYs1LMUHkTIGqMPJQ0oCBGfTzREs373iU,929
28
28
  megfile/lib/lazy_handler.py,sha256=f1rip2_T57vVo0WRNXve2bAa4LArvVheMfQg1S0vFzg,1915
29
- megfile/lib/s3_buffered_writer.py,sha256=AGjCNQ1X16kjFbEJouavkO6ykmlAtfVKBPAD-yYwAT0,6934
30
- megfile/lib/s3_cached_handler.py,sha256=e4KamTLMIPKa96yp7HGF05wDl2Yfoizz9pBrz-uAQ5w,1322
31
- megfile/lib/s3_limited_seekable_writer.py,sha256=NSBh5cZCCtwZM0DTwfPkpOA_h0NXd9-6qjasOby5zxc,6037
32
- megfile/lib/s3_memory_handler.py,sha256=jLBA5HVuI-UBPYMYN-B8iX_VGr8bC9brAqY-KbEGrtw,3725
33
- megfile/lib/s3_pipe_handler.py,sha256=38x8oPrxlXVWqMgDOqScPj0Pt2w2cQFSNoTK27EtBSw,3384
34
- megfile/lib/s3_prefetch_reader.py,sha256=yhY-ucs6BW1XgNDLC0xQ2lMrGVhc3Nk3hHr6GBfjRDA,4050
35
- megfile/lib/s3_share_cache_reader.py,sha256=QyZvzVpTswgiXv-E8QhV_jFdQjCBxVcgbgybXo6d1cM,3771
29
+ megfile/lib/s3_buffered_writer.py,sha256=9wiOXY7MgHrP7ulrN-QE2GcfwTfsTBniMxL9iDulpFw,7107
30
+ megfile/lib/s3_cached_handler.py,sha256=xuWiThi6pJtGL_ErSBmcu8rDv1XyXNmEhiFBnRF4NWU,1412
31
+ megfile/lib/s3_limited_seekable_writer.py,sha256=Dz4e5Gu-b9BoIzGHh5AAEkIGGUEB9Hg7MDToHS_05gk,6124
32
+ megfile/lib/s3_memory_handler.py,sha256=6Tj89xzc8z-FycVggGpjF_8lEbPsqRVB6undZwWsugo,3971
33
+ megfile/lib/s3_pipe_handler.py,sha256=hG8sEajO9dv9bLTeXsERxDioHHhzi4t8NC61lSbYk94,3557
34
+ megfile/lib/s3_prefetch_reader.py,sha256=vRZfFSV7bNliBrdD3cxgUrYSzLrgPPrzBT8zJMeAB8Q,4223
35
+ megfile/lib/s3_share_cache_reader.py,sha256=bPnD82lqrXtdLMegxyY15MzbWUHXuX0KKGtJHNOWD-w,3860
36
36
  megfile/lib/shadow_handler.py,sha256=IbFyTw107t-yWH0cGrDjAJX-CS3xeEr77_PTGsnSgk4,2683
37
37
  megfile/lib/stdio_handler.py,sha256=QDWtcZxz-hzi-rqQUiSlR3NrihX1fjK_Rj9T2mdTFEg,2044
38
38
  megfile/lib/url.py,sha256=VbQLjo0s4AaV0iSk66BcjI68aUTcN9zBZ5x6-cM4Qvs,103
39
39
  megfile/utils/__init__.py,sha256=qdX8FF_dYFKwp1BIWx3JeSGd91s7AKUDSEpDv9tORcM,9162
40
40
  megfile/utils/mutex.py,sha256=-2KH3bNovKRd9zvsXq9n3bWM7rQdoG9hO7tUPxVG_Po,2538
41
- megfile-2.2.5.post1.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
42
- megfile-2.2.5.post1.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
43
- megfile-2.2.5.post1.dist-info/METADATA,sha256=ELJJaAj7n2OxnVnaX_mwiEKuqAroHXgNqd_WzvffC8Y,10748
44
- megfile-2.2.5.post1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
45
- megfile-2.2.5.post1.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
46
- megfile-2.2.5.post1.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
47
- megfile-2.2.5.post1.dist-info/RECORD,,
41
+ megfile-2.2.6a1.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
42
+ megfile-2.2.6a1.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
43
+ megfile-2.2.6a1.dist-info/METADATA,sha256=rDzvBg6_knLWNEyWEX5k_afGpOcGkjNDk3XQoho_O7g,10744
44
+ megfile-2.2.6a1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
45
+ megfile-2.2.6a1.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
46
+ megfile-2.2.6a1.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
47
+ megfile-2.2.6a1.dist-info/RECORD,,