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 +12 -2
- megfile/cli.py +79 -2
- megfile/lib/compat.py +1 -1
- megfile/sftp_path.py +20 -9
- megfile/smart.py +1 -0
- megfile/version.py +1 -1
- {megfile-2.1.4.dist-info → megfile-2.2.0.dist-info}/METADATA +25 -2
- {megfile-2.1.4.dist-info → megfile-2.2.0.dist-info}/RECORD +13 -13
- {megfile-2.1.4.dist-info → megfile-2.2.0.dist-info}/LICENSE +0 -0
- {megfile-2.1.4.dist-info → megfile-2.2.0.dist-info}/LICENSE.pyre +0 -0
- {megfile-2.1.4.dist-info → megfile-2.2.0.dist-info}/WHEEL +0 -0
- {megfile-2.1.4.dist-info → megfile-2.2.0.dist-info}/entry_points.txt +0 -0
- {megfile-2.1.4.dist-info → megfile-2.2.0.dist-info}/top_level.txt +0 -0
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
|
-
"""
|
|
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
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:
|
|
479
|
-
|
|
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(
|
|
501
|
-
|
|
502
|
-
|
|
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
megfile/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = "2.
|
|
1
|
+
VERSION = "2.2.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: megfile
|
|
3
|
-
Version: 2.
|
|
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
|
|
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=
|
|
2
|
-
megfile/cli.py,sha256=
|
|
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=
|
|
14
|
-
megfile/smart.py,sha256=
|
|
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=
|
|
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=
|
|
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.
|
|
40
|
-
megfile-2.
|
|
41
|
-
megfile-2.
|
|
42
|
-
megfile-2.
|
|
43
|
-
megfile-2.
|
|
44
|
-
megfile-2.
|
|
45
|
-
megfile-2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|