megfile 2.1.4__py3-none-any.whl → 2.2.0__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/__init__.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from megfile.fs import fs_abspath, fs_access, fs_cwd, fs_exists, fs_expanduser, fs_getmd5, fs_getmtime, fs_getsize, fs_glob, fs_glob_stat, fs_home, fs_iglob, fs_isabs, fs_isdir, fs_isfile, fs_islink, fs_ismount, fs_listdir, fs_load_from, fs_lstat, fs_makedirs, fs_move, fs_readlink, fs_realpath, fs_relpath, fs_remove, fs_rename, fs_resolve, fs_save_as, fs_scan, fs_scan_stat, fs_scandir, fs_stat, fs_symlink, fs_sync, fs_unlink, fs_walk, is_fs
2
2
  from megfile.fs_path import FSPath
3
+ from megfile.http import http_exists, http_getmtime, http_getsize, http_open, http_stat, is_http
3
4
  from megfile.http_path import HttpPath, HttpsPath
4
5
  from megfile.s3 import is_s3, s3_access, s3_buffered_open, s3_cached_open, s3_concat, s3_copy, s3_download, s3_exists, s3_getmd5, s3_getmtime, s3_getsize, s3_glob, s3_glob_stat, s3_hasbucket, s3_iglob, s3_isdir, s3_isfile, s3_listdir, s3_load_content, s3_load_from, s3_lstat, s3_makedirs, s3_memory_open, s3_move, s3_open, s3_path_join, s3_pipe_open, s3_prefetch_open, s3_readlink, s3_remove, s3_rename, s3_save_as, s3_scan, s3_scan_stat, s3_scandir, s3_stat, s3_symlink, s3_sync, s3_unlink, s3_upload, s3_walk
5
6
  from megfile.s3_path import S3Path
@@ -7,12 +8,11 @@ from megfile.sftp import is_sftp, sftp_absolute, sftp_chmod, sftp_concat, sftp_c
7
8
  from megfile.sftp_path import SftpPath
8
9
  from megfile.smart import smart_access, smart_cache, smart_combine_open, smart_concat, smart_copy, smart_exists, smart_getmd5, smart_getmtime, smart_getsize, smart_glob, smart_glob_stat, smart_iglob, smart_isdir, smart_isfile, smart_islink, smart_listdir, smart_load_content, smart_load_from, smart_load_text, smart_lstat, smart_makedirs, smart_move, smart_open, smart_path_join, smart_readlink, smart_realpath, smart_remove, smart_rename, smart_save_as, smart_save_content, smart_save_text, smart_scan, smart_scan_stat, smart_scandir, smart_stat, smart_symlink, smart_sync, smart_touch, smart_unlink, smart_walk
9
10
  from megfile.smart_path import SmartPath
11
+ from megfile.stdio import is_stdio, stdio_open
10
12
  from megfile.stdio_path import StdioPath
11
13
  from megfile.version import VERSION as __version__
12
14
 
13
15
  __all__ = [
14
- 'is_fs',
15
- 'is_s3',
16
16
  'smart_access',
17
17
  'smart_cache',
18
18
  'smart_combine_open',
@@ -54,6 +54,7 @@ __all__ = [
54
54
  'smart_readlink',
55
55
  'smart_lstat',
56
56
  'smart_concat',
57
+ 'is_s3',
57
58
  's3_access',
58
59
  's3_buffered_open',
59
60
  's3_cached_open',
@@ -94,6 +95,7 @@ __all__ = [
94
95
  's3_symlink',
95
96
  's3_readlink',
96
97
  's3_concat',
98
+ 'is_fs',
97
99
  'fs_abspath',
98
100
  'fs_access',
99
101
  'fs_exists',
@@ -131,6 +133,14 @@ __all__ = [
131
133
  'fs_getmd5',
132
134
  'fs_symlink',
133
135
  'fs_readlink',
136
+ 'is_http',
137
+ 'http_open',
138
+ 'http_stat',
139
+ 'http_getsize',
140
+ 'http_getmtime',
141
+ 'http_exists',
142
+ 'is_stdio',
143
+ 'stdio_open',
134
144
  'is_sftp',
135
145
  'sftp_readlink',
136
146
  'sftp_absolute',
megfile/cli.py CHANGED
@@ -17,11 +17,12 @@ from megfile.version import VERSION
17
17
 
18
18
  logging.basicConfig(level=logging.ERROR)
19
19
  logging.getLogger('megfile').setLevel(level=logging.INFO)
20
+ DEFAULT_BLOCK_SIZE = 8 * 2**20 # 8MB
20
21
 
21
22
 
22
23
  @click.group()
23
24
  def cli():
24
- """Megfile Client"""
25
+ """Client"""
25
26
 
26
27
 
27
28
  def safe_cli(): # pragma: no cover
@@ -306,11 +307,87 @@ def cat(path: str):
306
307
  shutil.copyfileobj(file, sys.stdout.buffer)
307
308
 
308
309
 
310
+ @cli.command(
311
+ short_help='Concatenate any files and send first n lines of them to stdout.'
312
+ )
313
+ @click.argument('path')
314
+ @click.option(
315
+ '-n',
316
+ '--lines',
317
+ type=click.INT,
318
+ default=10,
319
+ help='print the first NUM lines')
320
+ def head(path: str, lines: int):
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
+ for _ in range(lines):
326
+ click.echo(f.readline().strip(b'\n'))
327
+ if f.tell() >= file_size:
328
+ break
329
+
330
+
331
+ @cli.command(
332
+ short_help='Concatenate any files and send last n lines of them to stdout.')
333
+ @click.argument('path')
334
+ @click.option(
335
+ '-n',
336
+ '--lines',
337
+ type=click.INT,
338
+ default=10,
339
+ help='print the last NUM lines')
340
+ def tail(path: str, lines: int):
341
+ line_list = []
342
+ with smart_open(path, 'rb') as f:
343
+ f.seek(0, os.SEEK_END)
344
+ file_size = f.tell()
345
+ f.seek(0, os.SEEK_SET)
346
+
347
+ for current_offset in range(file_size - DEFAULT_BLOCK_SIZE,
348
+ 0 - DEFAULT_BLOCK_SIZE,
349
+ -DEFAULT_BLOCK_SIZE):
350
+ current_offset = max(0, current_offset)
351
+ f.seek(current_offset)
352
+ block_lines = f.read(DEFAULT_BLOCK_SIZE).split(b'\n')
353
+ if len(line_list) > 0:
354
+ block_lines[-1] += line_list[0]
355
+ block_lines.extend(line_list[1:])
356
+ if len(block_lines) > lines:
357
+ line_list = block_lines[-lines:]
358
+ break
359
+ else:
360
+ line_list = block_lines
361
+ for line in line_list:
362
+ click.echo(line)
363
+
364
+
365
+ @cli.command(short_help='Write bytes from stdin to file.')
366
+ @click.argument('path')
367
+ @click.option('-a', '--append', is_flag=True, help='Append to the given file')
368
+ @click.option(
369
+ '-o', '--stdout', is_flag=True, help='File content to standard output')
370
+ def to(path: str, append: bool, stdout: bool):
371
+ mode = 'wb'
372
+ if append:
373
+ mode = 'ab'
374
+ with smart_open('stdio://0', 'rb') as stdin, smart_open(
375
+ path, mode) as f, smart_open('stdio://1', 'wb') as stdout_fd:
376
+ length = 16 * 1024
377
+ while True:
378
+ buf = stdin.read(length)
379
+ if not buf:
380
+ break
381
+ f.write(buf)
382
+ if stdout:
383
+ stdout_fd.write(buf)
384
+
385
+
309
386
  @cli.command(
310
387
  short_help='Produce an md5sum file for all the objects in the path.')
311
388
  @click.argument('path')
312
389
  def md5sum(path: str):
313
- click.echo(smart_getmd5(path))
390
+ click.echo(smart_getmd5(path, recalculate=True))
314
391
 
315
392
 
316
393
  @cli.command(
megfile/lib/compat.py CHANGED
@@ -19,7 +19,7 @@ import sys
19
19
 
20
20
  if sys.version_info.major == 3 and sys.version_info.minor >= 8:
21
21
  from shutil import copytree
22
- else:
22
+ else: # pragma: no cover
23
23
  from shutil import Error, copy2, copystat
24
24
 
25
25
  def copytree(
megfile/sftp_path.py CHANGED
@@ -475,8 +475,11 @@ def sftp_concat(src_paths: List[PathLike], dst_path: PathLike) -> None:
475
475
  class SftpPath(URIPath):
476
476
  """sftp protocol
477
477
 
478
- uri format: sftp://[username[:password]@]hostname[:port]/file_path
479
- e.g. sftp://username:password@127.0.0.1:22/data/test/
478
+ uri format:
479
+ - absolute path
480
+ - sftp://[username[:password]@]hostname[:port]//file_path
481
+ - relative path
482
+ - - sftp://[username[:password]@]hostname[:port]/file_path
480
483
  """
481
484
 
482
485
  protocol = "sftp"
@@ -484,10 +487,13 @@ class SftpPath(URIPath):
484
487
  def __init__(self, path: "PathLike", *other_paths: "PathLike"):
485
488
  super().__init__(path, *other_paths)
486
489
  parts = urlsplit(self.path)
487
- self._real_path = parts.path
488
- if not self._real_path.startswith('/'):
489
- self._real_path = f"/{self._real_path}"
490
490
  self._urlsplit_parts = parts
491
+ self._real_path = parts.path
492
+ if parts.path.startswith('//'):
493
+ self._root_dir = '/'
494
+ else:
495
+ self._root_dir = self._client.normalize('.')
496
+ self._real_path = os.path.join(self._root_dir, parts.path.lstrip('/'))
491
497
 
492
498
  @property
493
499
  def _client(self):
@@ -497,9 +503,14 @@ class SftpPath(URIPath):
497
503
  username=self._urlsplit_parts.username,
498
504
  password=self._urlsplit_parts.password)
499
505
 
500
- def _generate_path_object(self, sftp_local_path: str):
501
- new_parts = self._urlsplit_parts._replace(
502
- path=sftp_local_path.lstrip('/'))
506
+ def _generate_path_object(
507
+ self, sftp_local_path: str, resolve: bool = False):
508
+ if resolve or self._root_dir == '/':
509
+ sftp_local_path = f"//{sftp_local_path.lstrip('/')}"
510
+ else:
511
+ sftp_local_path = os.path.relpath(
512
+ sftp_local_path, start=self._root_dir)
513
+ new_parts = self._urlsplit_parts._replace(path=sftp_local_path)
503
514
  return self.from_path(urlunsplit(new_parts))
504
515
 
505
516
  def exists(self, followlinks: bool = False) -> bool:
@@ -971,7 +982,7 @@ class SftpPath(URIPath):
971
982
  :rtype: SftpPath
972
983
  '''
973
984
  path = self._client.normalize(self._real_path)
974
- return self._generate_path_object(path)
985
+ return self._generate_path_object(path, resolve=True)
975
986
 
976
987
  def md5(self, recalculate: bool = False, followlinks: bool = True):
977
988
  '''
megfile/smart.py CHANGED
@@ -64,6 +64,7 @@ __all__ = [
64
64
  'smart_readlink',
65
65
  'register_copy_func',
66
66
  'smart_concat',
67
+ 'SmartCacher',
67
68
  ]
68
69
 
69
70
 
megfile/version.py CHANGED
@@ -1 +1 @@
1
- VERSION = "2.1.4"
1
+ VERSION = "2.2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: megfile
3
- Version: 2.1.4
3
+ Version: 2.2.0
4
4
  Summary: Megvii file operation library
5
5
  Home-page: https://github.com/megvii-research/megfile
6
6
  Author: megvii
@@ -62,6 +62,29 @@ megfile - Megvii FILE library
62
62
 
63
63
  Here's an example of writing a file to s3 / sftp / fs, syncing to local, reading and finally deleting it.
64
64
 
65
+ ### Path Format
66
+ - local file
67
+ - unix filesystem path
68
+ - examples:
69
+ - `/data/test.txt`
70
+ - `test.txt`
71
+ - 1
72
+ - oss
73
+ - `s3[+profile_name]://bucket/key`
74
+ - sftp
75
+ - `sftp://[username[:password]@]hostname[:port]//absolute_file_path`
76
+ - `sftp://[username[:password]@]hostname[:port]/relative_file_path`
77
+ - http
78
+ - http / https url
79
+ - examples:
80
+ - `http://hostname/test`
81
+ - `https://hostname/test`
82
+ - stdio
83
+ - `stdio://-`
84
+ - `stdio://0`
85
+ - `stdio://1`
86
+ - `stdio://2`
87
+
65
88
  ### Functional Interface
66
89
  ```python
67
90
  from megfile import smart_open, smart_exists, smart_sync, smart_remove, smart_glob
@@ -201,7 +224,7 @@ s3 =
201
224
  megfile.smart_copy('s3+profile1://bucket/key', 's3+profile2://bucket/key')
202
225
  ```
203
226
 
204
- sftp path format is `sftp://[username[:password]@]hostname[:port]/file_path`, and sftp support some environments:
227
+ sftp support some environments:
205
228
  ```
206
229
  # If you are not set username or password in path, you can set them in environments
207
230
  $ export SFTP_USERNAME=user
@@ -1,5 +1,5 @@
1
- megfile/__init__.py,sha256=wlijLJS6F8Vdm1xjpsjd9fKBeDGpgIMrVsXYSeOQ4Xw,5434
2
- megfile/cli.py,sha256=5WnLtC2PBXfNDB4h9i4idjMEwu334MGXz-VdbfHoed8,10396
1
+ megfile/__init__.py,sha256=Qsi3XNP_0XYoSol-1AGutZqo0rfBnzaiZ-HVXll4fB0,5721
2
+ megfile/cli.py,sha256=zB6a1QjvIXqmd4nQR9YSTy3RH61pTX14E63uICjIRG8,12797
3
3
  megfile/errors.py,sha256=H5wCiVBvOtQo5cu3JLhAUCpQJsCkPNm1KNw9o8y4Las,11349
4
4
  megfile/fs.py,sha256=sjkm_LsvNCw8hj9Ee-1HSNzvg7bRHTPem8KTDDBQlCw,11621
5
5
  megfile/fs_path.py,sha256=Lz-u8XL2RMViHl_39yapAwX5XSE_ZpQsuhAvVve6rk8,38532
@@ -10,16 +10,16 @@ megfile/pathlike.py,sha256=52e6POtMfUCC3Hb9XNwBLXM3Gkz3aGP8H8AagGKlDSg,29307
10
10
  megfile/s3.py,sha256=6d9bBVkVdXIvmJLfpOgJkK4nVAsLR3lirrB6x1-P2y8,12437
11
11
  megfile/s3_path.py,sha256=2AY_Rcn0ZR2TpPSqWxBcbUuQ3JuS7XerZ-wBK4wXyMo,84754
12
12
  megfile/sftp.py,sha256=qzfgI-MGzNsr7adUQaiVKS7zRHGuK-Hs6o45wNIAcww,11943
13
- megfile/sftp_path.py,sha256=Gb-x0H3ziX5N7pMxj768-ootIfn5ZTyATi_gT4FWqMw,46668
14
- megfile/smart.py,sha256=GbQrOPAc_KUd4MarYdgBwjtTeMqFDF8J4FULqAvWaB4,32675
13
+ megfile/sftp_path.py,sha256=h_NeZtkKJ44hBIuhvBbLUlADm02uEkRT2T4PBU44uP4,47103
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=INwNgAtJTWwjcC9CT2Iw7J62gdGUKLQhNVAD0EOp6H4,19
18
+ megfile/version.py,sha256=SX94SfG1HNW6IdIYW_iqO17A0qZmHZUfyXnyAzilMUs,19
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
22
- megfile/lib/compat.py,sha256=6m4eIwCndB8CbIl0FRx0Y0tg8VAcjdRLHma2bdWPO0k,3013
22
+ megfile/lib/compat.py,sha256=rYjfzQ3svuY7pB37W1JGyWH1kxd9aT4RtIe90npPtXI,3033
23
23
  megfile/lib/fnmatch.py,sha256=HgdlnEWBsdFUOZqnW_v1kj1jeH_9lMcCqW85pyMu4vM,4054
24
24
  megfile/lib/glob.py,sha256=7i9dIput9rI9JIPyTZX-JDmFS7IP_THlX1k-35foAfw,9732
25
25
  megfile/lib/joinpath.py,sha256=D4Px6-lnDDpYs1LMUHkTIGqMPJQ0oCBGfTzREs373iU,929
@@ -36,10 +36,10 @@ megfile/lib/stdio_handler.py,sha256=QDWtcZxz-hzi-rqQUiSlR3NrihX1fjK_Rj9T2mdTFEg,
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.1.4.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
40
- megfile-2.1.4.dist-info/LICENSE.pyre,sha256=9lf5nT-5ZH25JijpYAequ0bl8E8z5JmZB1qrjiUMp84,1080
41
- megfile-2.1.4.dist-info/METADATA,sha256=m5WS4ZzezadAsLn4UK7HNlIaTnOHGJc1cCWyaXJwqVk,10154
42
- megfile-2.1.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
43
- megfile-2.1.4.dist-info/entry_points.txt,sha256=M6ZWSSv5_5_QtIpZafy3vq7WuOJ_5dSGQQnEZbByt2Q,49
44
- megfile-2.1.4.dist-info/top_level.txt,sha256=i3rMgdU1ZAJekAceojhA-bkm3749PzshtRmLTbeLUPQ,8
45
- megfile-2.1.4.dist-info/RECORD,,
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=5hJWi8RWnKtRNaoubN8ZWAtJ-x62XVGsDUEjN9XVI-4,10595
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,,