cloud-files 4.21.1__py3-none-any.whl → 4.23.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.
- {cloud_files-4.21.1.dist-info → cloud_files-4.23.0.dist-info}/AUTHORS +1 -0
- {cloud_files-4.21.1.dist-info → cloud_files-4.23.0.dist-info}/METADATA +2 -5
- cloud_files-4.23.0.dist-info/RECORD +26 -0
- {cloud_files-4.21.1.dist-info → cloud_files-4.23.0.dist-info}/entry_points.txt +0 -1
- cloud_files-4.23.0.dist-info/pbr.json +1 -0
- cloudfiles/cloudfiles.py +48 -16
- cloudfiles/connectionpools.py +14 -5
- cloudfiles/interfaces.py +8 -1
- cloudfiles/paths.py +2 -0
- cloudfiles/secrets.py +9 -7
- cloudfiles_cli/cloudfiles_cli.py +33 -17
- cloud_files-4.21.1.dist-info/RECORD +0 -26
- cloud_files-4.21.1.dist-info/pbr.json +0 -1
- {cloud_files-4.21.1.dist-info → cloud_files-4.23.0.dist-info}/LICENSE +0 -0
- {cloud_files-4.21.1.dist-info → cloud_files-4.23.0.dist-info}/WHEEL +0 -0
- {cloud_files-4.21.1.dist-info → cloud_files-4.23.0.dist-info}/top_level.txt +0 -0
|
@@ -2,4 +2,5 @@ Manuel Castro <macastro@princeton.edu>
|
|
|
2
2
|
Nico Kemnitz <nkemnitz@princeton.edu>
|
|
3
3
|
V24 <55334829+umarfarouk98@users.noreply.github.com>
|
|
4
4
|
William Silversmith <william.silversmith@gmail.com>
|
|
5
|
+
madiganz <madiganz@users.noreply.github.com>
|
|
5
6
|
ranlu <ranlu@users.noreply.github.com>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cloud-files
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.23.0
|
|
4
4
|
Summary: Fast access to cloud storage and local FS.
|
|
5
5
|
Home-page: https://github.com/seung-lab/cloud-files/
|
|
6
6
|
Author: William Silversmith
|
|
7
7
|
Author-email: ws9@princeton.edu
|
|
8
8
|
License: License :: OSI Approved :: BSD License
|
|
9
|
-
Platform: UNKNOWN
|
|
10
9
|
Classifier: Intended Audience :: Developers
|
|
11
10
|
Classifier: Development Status :: 4 - Beta
|
|
12
11
|
Classifier: License :: OSI Approved :: BSD License
|
|
@@ -47,7 +46,7 @@ Provides-Extra: numpy
|
|
|
47
46
|
Requires-Dist: numpy ; extra == 'numpy'
|
|
48
47
|
Provides-Extra: test
|
|
49
48
|
Requires-Dist: pytest ; extra == 'test'
|
|
50
|
-
Requires-Dist: moto ; extra == 'test'
|
|
49
|
+
Requires-Dist: moto (>=5) ; extra == 'test'
|
|
51
50
|
|
|
52
51
|
[](https://badge.fury.io/py/cloud-files) [](https://github.com/seung-lab/cloud-files/actions?query=workflow%3A%22Test+Suite%22)
|
|
53
52
|
|
|
@@ -526,5 +525,3 @@ CloudFiles is derived from the [CloudVolume.Storage](https://github.com/seung-la
|
|
|
526
525
|
|
|
527
526
|
Storage was initially created by William Silversmith and Ignacio Tartavull. It was maintained and improved by William Silversmith and includes improvements by Nico Kemnitz (extremely fast exists), Ben Falk (brotli), and Ran Lu (local file locking). Manuel Castro added the ability to chose cloud storage class. Thanks to the anonymous author from https://teppen.io/ for their s3 etag validation code.
|
|
528
527
|
|
|
529
|
-
|
|
530
|
-
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
cloudfiles/__init__.py,sha256=pLB4CcV2l3Jgv_ni1520Np1pfzFj8Cpr87vNxFT3rNI,493
|
|
2
|
+
cloudfiles/buckets.py,sha256=eRAYdDfvVpNyJyK5ryDRMwgNJUeEuFBJ6doWU2JkAcA,74
|
|
3
|
+
cloudfiles/cloudfiles.py,sha256=OWTQe-Lkz60E6YFrFXhqWVl1L3_3cqzRl15Lqr09nYs,43794
|
|
4
|
+
cloudfiles/compression.py,sha256=pqYdpu5vfFv-094BpfZ2pgRjVu7ESM9pAZC09P6E8bY,6150
|
|
5
|
+
cloudfiles/connectionpools.py,sha256=aL8RiSjRepECfgAFmJcz80aJFKbou7hsbuEgugDKwB8,4814
|
|
6
|
+
cloudfiles/exceptions.py,sha256=H2IcMlZoy2Bsn-6wCPwyLDjg66LZCyxtcf3s_p21FDw,770
|
|
7
|
+
cloudfiles/gcs.py,sha256=_njJ7TpqwrHCjPHRGkBN5alCrCWKM2m9qdy5DhxMZ7U,3718
|
|
8
|
+
cloudfiles/interfaces.py,sha256=j60PSGqCmeE_7o7gBUW-pi56up4fvIaX3qOlxW_fqMQ,33540
|
|
9
|
+
cloudfiles/lib.py,sha256=fEqL5APu_WQhl2yxqQbwE7msHdu7U8pstAJw6LgoKO0,5142
|
|
10
|
+
cloudfiles/paths.py,sha256=tqR9XnRdAKopTJqSM6V5xrMo1xfmBdl9b5DpBLZnoB0,9998
|
|
11
|
+
cloudfiles/resumable_tools.py,sha256=pK-VcoPjQ2BjGjvlvH4dDCBf6lNsqHG-weiBgxVFbzA,5838
|
|
12
|
+
cloudfiles/scheduler.py,sha256=DqDANmOpB3NdzFgJDNMMibRIkCrXQqIh2XGL8GWoc9c,3668
|
|
13
|
+
cloudfiles/secrets.py,sha256=3BSV2Hn8FGGn4QCs5FP3eGs4WEs5cIXRBsXuF0eIgIY,4918
|
|
14
|
+
cloudfiles/threaded_queue.py,sha256=Nl4vfXhQ6nDLF8PZpSSBpww0M2zWtcd4DLs3W3BArBw,7082
|
|
15
|
+
cloudfiles/typing.py,sha256=f3ZYkNfN9poxhGu5j-P0KCxjCCqSn9HAg5KiIPkjnCg,416
|
|
16
|
+
cloudfiles_cli/LICENSE,sha256=Jna4xYE8CCQmaxjr5Fs-wmUBnIQJ1DGcNn9MMjbkprk,1538
|
|
17
|
+
cloudfiles_cli/__init__.py,sha256=Wftt3R3F21QsHtWqx49ODuqT9zcSr0em7wk48kcH0WM,29
|
|
18
|
+
cloudfiles_cli/cloudfiles_cli.py,sha256=eETIOK4QyztQcpA4ZRny21SobLtcrPDlzZ_JaKBmmmA,28449
|
|
19
|
+
cloud_files-4.23.0.dist-info/AUTHORS,sha256=7E2vC894bbLPO_kvUuEB2LFZZbIxZn23HabxH7x0Hgo,266
|
|
20
|
+
cloud_files-4.23.0.dist-info/LICENSE,sha256=Jna4xYE8CCQmaxjr5Fs-wmUBnIQJ1DGcNn9MMjbkprk,1538
|
|
21
|
+
cloud_files-4.23.0.dist-info/METADATA,sha256=1V4s9l7YchiO-D_9yqdVqSHQmK59lvWmda27YDXiGtc,26804
|
|
22
|
+
cloud_files-4.23.0.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92
|
|
23
|
+
cloud_files-4.23.0.dist-info/entry_points.txt,sha256=xlirb1FVhn1mbcv4IoyMEGumDqKOA4VMVd3drsRQxIg,51
|
|
24
|
+
cloud_files-4.23.0.dist-info/pbr.json,sha256=yW5BCBFnMvccatJ349ZLnNWUR137dFenl6ygMDm5k1c,46
|
|
25
|
+
cloud_files-4.23.0.dist-info/top_level.txt,sha256=xPyrST3okJbsmdCF5IC2gYAVxg_aD5AYVTnNo8UuoZU,26
|
|
26
|
+
cloud_files-4.23.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"git_version": "a123f94", "is_release": true}
|
cloudfiles/cloudfiles.py
CHANGED
|
@@ -83,8 +83,7 @@ def parallelize(desc=None, returns_list=False):
|
|
|
83
83
|
sig = inspect.signature(fn).bind(*args, **kwargs)
|
|
84
84
|
parallel = sig.arguments.get("parallel", None)
|
|
85
85
|
except TypeError:
|
|
86
|
-
parallel = kwargs.
|
|
87
|
-
del kwargs["parallel"]
|
|
86
|
+
parallel = kwargs.pop("parallel", None)
|
|
88
87
|
sig = inspect.signature(fn).bind_partial(*args, **kwargs)
|
|
89
88
|
|
|
90
89
|
params = sig.arguments
|
|
@@ -251,7 +250,8 @@ class CloudFiles:
|
|
|
251
250
|
parallel:ParallelType = 1, request_payer:Optional[str] = None,
|
|
252
251
|
locking:Optional[bool] = None,
|
|
253
252
|
lock_dir:Optional[str] = None,
|
|
254
|
-
composite_upload_threshold:int = int(1e8)
|
|
253
|
+
composite_upload_threshold:int = int(1e8),
|
|
254
|
+
no_sign_request:bool = False,
|
|
255
255
|
):
|
|
256
256
|
if use_https:
|
|
257
257
|
cloudpath = paths.to_https_protocol(cloudpath)
|
|
@@ -265,6 +265,7 @@ class CloudFiles:
|
|
|
265
265
|
self.request_payer = request_payer
|
|
266
266
|
self.locking = locking
|
|
267
267
|
self.composite_upload_threshold = composite_upload_threshold
|
|
268
|
+
self.no_sign_request = bool(no_sign_request)
|
|
268
269
|
|
|
269
270
|
self._lock_dir = lock_dir
|
|
270
271
|
self._path = paths.extract(cloudpath)
|
|
@@ -315,6 +316,7 @@ class CloudFiles:
|
|
|
315
316
|
locking=self.locking,
|
|
316
317
|
lock_dir=self.lock_dir,
|
|
317
318
|
composite_upload_threshold=self.composite_upload_threshold,
|
|
319
|
+
no_sign_request=self.no_sign_request,
|
|
318
320
|
)
|
|
319
321
|
|
|
320
322
|
@property
|
|
@@ -456,6 +458,8 @@ class CloudFiles:
|
|
|
456
458
|
num_threads = self.num_threads
|
|
457
459
|
if self.protocol == "file":
|
|
458
460
|
num_threads = 1
|
|
461
|
+
elif self.protocol == "mem":
|
|
462
|
+
num_threads = 0
|
|
459
463
|
|
|
460
464
|
results = schedule_jobs(
|
|
461
465
|
fns=( partial(download, path) for path in paths ),
|
|
@@ -517,7 +521,7 @@ class CloudFiles:
|
|
|
517
521
|
def puts(
|
|
518
522
|
self, files:PutType,
|
|
519
523
|
content_type:Optional[str] = None, compress:CompressType = None,
|
|
520
|
-
compression_level:Optional[int]=None, cache_control:Optional[str] = None,
|
|
524
|
+
compression_level:Optional[int] = None, cache_control:Optional[str] = None,
|
|
521
525
|
total:Optional[int] = None, raw:bool = False, progress:Optional[bool] = None,
|
|
522
526
|
parallel:ParallelType = 1, storage_class:Optional[str] = None
|
|
523
527
|
) -> int:
|
|
@@ -941,8 +945,12 @@ class CloudFiles:
|
|
|
941
945
|
yield f
|
|
942
946
|
|
|
943
947
|
def transfer_to(
|
|
944
|
-
self,
|
|
945
|
-
|
|
948
|
+
self,
|
|
949
|
+
cf_dest:Any,
|
|
950
|
+
paths:Any = None, # recursive CloudFiles not supported as type
|
|
951
|
+
block_size:int = 64,
|
|
952
|
+
reencode:Optional[str] = None,
|
|
953
|
+
content_type:Optional[str] = None,
|
|
946
954
|
) -> None:
|
|
947
955
|
"""
|
|
948
956
|
Transfer all files from this CloudFiles storage
|
|
@@ -975,6 +983,8 @@ class CloudFiles:
|
|
|
975
983
|
block_size: number of files to transfer per a batch
|
|
976
984
|
reencode: if not None, reencode the compression type
|
|
977
985
|
as '' (None), 'gzip', 'br', 'zstd'
|
|
986
|
+
content_type: if provided, set the Content-Type header
|
|
987
|
+
on the upload. This is necessary for e.g. file->cloud
|
|
978
988
|
"""
|
|
979
989
|
if isinstance(cf_dest, str):
|
|
980
990
|
cf_dest = CloudFiles(
|
|
@@ -982,11 +992,15 @@ class CloudFiles:
|
|
|
982
992
|
green=self.green, num_threads=self.num_threads,
|
|
983
993
|
)
|
|
984
994
|
|
|
985
|
-
return cf_dest.transfer_from(self, paths, block_size, reencode)
|
|
995
|
+
return cf_dest.transfer_from(self, paths, block_size, reencode, content_type)
|
|
986
996
|
|
|
987
997
|
def transfer_from(
|
|
988
|
-
self,
|
|
989
|
-
|
|
998
|
+
self,
|
|
999
|
+
cf_src:Any,
|
|
1000
|
+
paths:Any = None, # recursive CloudFiles not supported as type
|
|
1001
|
+
block_size:int = 64,
|
|
1002
|
+
reencode:Optional[str] = None,
|
|
1003
|
+
content_type:Optional[str] = None,
|
|
990
1004
|
) -> None:
|
|
991
1005
|
"""
|
|
992
1006
|
Transfer all files from the source CloudFiles storage
|
|
@@ -1019,6 +1033,8 @@ class CloudFiles:
|
|
|
1019
1033
|
block_size: number of files to transfer per a batch
|
|
1020
1034
|
reencode: if not None, reencode the compression type
|
|
1021
1035
|
as '' (None), 'gzip', 'br', 'zstd'
|
|
1036
|
+
content_type: if provided, set the Content-Type header
|
|
1037
|
+
on the upload. This is necessary for e.g. file->cloud
|
|
1022
1038
|
"""
|
|
1023
1039
|
if isinstance(cf_src, str):
|
|
1024
1040
|
cf_src = CloudFiles(
|
|
@@ -1043,7 +1059,10 @@ class CloudFiles:
|
|
|
1043
1059
|
and self.protocol != "file"
|
|
1044
1060
|
and reencode is None
|
|
1045
1061
|
):
|
|
1046
|
-
self.__transfer_file_to_remote(
|
|
1062
|
+
self.__transfer_file_to_remote(
|
|
1063
|
+
cf_src, self, paths, total,
|
|
1064
|
+
pbar, block_size, content_type
|
|
1065
|
+
)
|
|
1047
1066
|
elif (
|
|
1048
1067
|
(
|
|
1049
1068
|
(cf_src.protocol == "gs" and self.protocol == "gs")
|
|
@@ -1055,14 +1074,21 @@ class CloudFiles:
|
|
|
1055
1074
|
)
|
|
1056
1075
|
and reencode is None
|
|
1057
1076
|
):
|
|
1058
|
-
self.__transfer_cloud_internal(
|
|
1077
|
+
self.__transfer_cloud_internal(
|
|
1078
|
+
cf_src, self, paths,
|
|
1079
|
+
total, pbar, block_size
|
|
1080
|
+
)
|
|
1059
1081
|
else:
|
|
1060
|
-
self.__transfer_general(
|
|
1082
|
+
self.__transfer_general(
|
|
1083
|
+
cf_src, self, paths, total,
|
|
1084
|
+
pbar, block_size,
|
|
1085
|
+
reencode, content_type
|
|
1086
|
+
)
|
|
1061
1087
|
|
|
1062
1088
|
def __transfer_general(
|
|
1063
1089
|
self, cf_src, cf_dest, paths,
|
|
1064
1090
|
total, pbar, block_size,
|
|
1065
|
-
reencode
|
|
1091
|
+
reencode, content_type
|
|
1066
1092
|
):
|
|
1067
1093
|
"""
|
|
1068
1094
|
Downloads the file into RAM, transforms
|
|
@@ -1089,7 +1115,13 @@ class CloudFiles:
|
|
|
1089
1115
|
item["path"] = item["tags"]["dest_path"]
|
|
1090
1116
|
del item["tags"]["dest_path"]
|
|
1091
1117
|
yield item
|
|
1092
|
-
self.puts(
|
|
1118
|
+
self.puts(
|
|
1119
|
+
renameiter(),
|
|
1120
|
+
raw=True,
|
|
1121
|
+
progress=False,
|
|
1122
|
+
compress=reencode,
|
|
1123
|
+
content_type=content_type,
|
|
1124
|
+
)
|
|
1093
1125
|
pbar.update(len(block_paths))
|
|
1094
1126
|
|
|
1095
1127
|
def __transfer_file_to_file(
|
|
@@ -1121,7 +1153,7 @@ class CloudFiles:
|
|
|
1121
1153
|
|
|
1122
1154
|
def __transfer_file_to_remote(
|
|
1123
1155
|
self, cf_src, cf_dest, paths,
|
|
1124
|
-
total, pbar, block_size
|
|
1156
|
+
total, pbar, block_size, content_type
|
|
1125
1157
|
):
|
|
1126
1158
|
"""
|
|
1127
1159
|
Provide file handles instead of slurped binaries
|
|
@@ -1147,7 +1179,7 @@ class CloudFiles:
|
|
|
1147
1179
|
"content": open(handle_path, "rb"),
|
|
1148
1180
|
"compress": encoding,
|
|
1149
1181
|
})
|
|
1150
|
-
cf_dest.puts(to_upload, raw=True, progress=False)
|
|
1182
|
+
cf_dest.puts(to_upload, raw=True, progress=False, content_type=content_type)
|
|
1151
1183
|
for item in to_upload:
|
|
1152
1184
|
item["content"].close()
|
|
1153
1185
|
pbar.update(len(block_paths))
|
cloudfiles/connectionpools.py
CHANGED
|
@@ -7,6 +7,9 @@ import time
|
|
|
7
7
|
from functools import partial
|
|
8
8
|
|
|
9
9
|
import boto3
|
|
10
|
+
from botocore import UNSIGNED
|
|
11
|
+
from botocore.config import Config
|
|
12
|
+
|
|
10
13
|
from google.cloud.storage import Client
|
|
11
14
|
from google.oauth2 import service_account
|
|
12
15
|
import tenacity
|
|
@@ -55,13 +58,13 @@ class ConnectionPool(object):
|
|
|
55
58
|
def _create_connection(self, secrets, endpoint):
|
|
56
59
|
raise NotImplementedError
|
|
57
60
|
|
|
58
|
-
def get_connection(self, secrets=None, endpoint=None):
|
|
61
|
+
def get_connection(self, secrets=None, endpoint=None, no_sign_request=False):
|
|
59
62
|
with self._lock:
|
|
60
63
|
try:
|
|
61
64
|
conn = self.pool.get(block=False)
|
|
62
65
|
self.pool.task_done()
|
|
63
66
|
except queue.Empty:
|
|
64
|
-
conn = self._create_connection(secrets, endpoint)
|
|
67
|
+
conn = self._create_connection(secrets, endpoint, no_sign_request)
|
|
65
68
|
finally:
|
|
66
69
|
self.outstanding += 1
|
|
67
70
|
|
|
@@ -103,7 +106,7 @@ class S3ConnectionPool(ConnectionPool):
|
|
|
103
106
|
super(S3ConnectionPool, self).__init__()
|
|
104
107
|
|
|
105
108
|
@retry
|
|
106
|
-
def _create_connection(self, secrets=None, endpoint=None):
|
|
109
|
+
def _create_connection(self, secrets=None, endpoint=None, no_sign_request=False):
|
|
107
110
|
if secrets is None:
|
|
108
111
|
secrets = self.credentials
|
|
109
112
|
if isinstance(secrets, str):
|
|
@@ -113,11 +116,17 @@ class S3ConnectionPool(ConnectionPool):
|
|
|
113
116
|
if endpoint is not None:
|
|
114
117
|
additional_args['endpoint_url'] = endpoint
|
|
115
118
|
|
|
119
|
+
config = None
|
|
120
|
+
if no_sign_request:
|
|
121
|
+
config = Config(signature_version=UNSIGNED)
|
|
122
|
+
|
|
116
123
|
return boto3.client(
|
|
117
124
|
's3',
|
|
118
125
|
aws_access_key_id=secrets.get('AWS_ACCESS_KEY_ID', None),
|
|
119
126
|
aws_secret_access_key=secrets.get('AWS_SECRET_ACCESS_KEY', None),
|
|
127
|
+
aws_session_token=secrets.get('AWS_SESSION_TOKEN', None),
|
|
120
128
|
region_name=secrets.get('AWS_DEFAULT_REGION', 'us-east-1'),
|
|
129
|
+
config=config,
|
|
121
130
|
**additional_args
|
|
122
131
|
)
|
|
123
132
|
|
|
@@ -135,7 +144,7 @@ class GCloudBucketPool(ConnectionPool):
|
|
|
135
144
|
super(GCloudBucketPool, self).__init__()
|
|
136
145
|
|
|
137
146
|
@retry
|
|
138
|
-
def _create_connection(self, secrets=None, endpoint=None):
|
|
147
|
+
def _create_connection(self, secrets=None, endpoint=None, no_sign_request=False):
|
|
139
148
|
if secrets is None:
|
|
140
149
|
secrets = self.credentials
|
|
141
150
|
|
|
@@ -162,7 +171,7 @@ class MemoryPool(ConnectionPool):
|
|
|
162
171
|
self.data = MEMORY_DATA
|
|
163
172
|
super(MemoryPool, self).__init__()
|
|
164
173
|
|
|
165
|
-
def _create_connection(self, secrets=None, endpoint=None):
|
|
174
|
+
def _create_connection(self, secrets=None, endpoint=None, no_sign_request=False):
|
|
166
175
|
if self.bucket not in self.data:
|
|
167
176
|
self.data[self.bucket] = {}
|
|
168
177
|
return self.data[self.bucket]
|
cloudfiles/interfaces.py
CHANGED
|
@@ -806,7 +806,13 @@ class S3Interface(StorageInterface):
|
|
|
806
806
|
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Bucket.delete_objects
|
|
807
807
|
# claims batch size limit is 1000
|
|
808
808
|
delete_batch_size = 1000
|
|
809
|
-
def __init__(
|
|
809
|
+
def __init__(
|
|
810
|
+
self, path, secrets=None,
|
|
811
|
+
request_payer=None,
|
|
812
|
+
composite_upload_threshold=int(1e8),
|
|
813
|
+
no_sign_request=False,
|
|
814
|
+
**kwargs
|
|
815
|
+
):
|
|
810
816
|
super(StorageInterface, self).__init__()
|
|
811
817
|
global S3_POOL
|
|
812
818
|
|
|
@@ -823,6 +829,7 @@ class S3Interface(StorageInterface):
|
|
|
823
829
|
self._conn = self._get_bucket(path.bucket)
|
|
824
830
|
|
|
825
831
|
self.composite_upload_threshold = composite_upload_threshold
|
|
832
|
+
self.no_sign_request = no_sign_request
|
|
826
833
|
|
|
827
834
|
def _get_bucket(self, bucket_name):
|
|
828
835
|
global S3_BUCKET_POOL_LOCK
|
cloudfiles/paths.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from functools import lru_cache
|
|
1
2
|
from collections import namedtuple
|
|
2
3
|
import orjson
|
|
3
4
|
import os.path
|
|
@@ -295,6 +296,7 @@ def extract_format_protocol(cloudpath:str) -> tuple:
|
|
|
295
296
|
|
|
296
297
|
return (fmt, proto, endpoint, cloudpath, alias)
|
|
297
298
|
|
|
299
|
+
@lru_cache(maxsize=10, typed=False)
|
|
298
300
|
def extract(cloudpath:str, windows=None) -> ExtractedPath:
|
|
299
301
|
"""
|
|
300
302
|
Given a valid cloudpath of the form
|
cloudfiles/secrets.py
CHANGED
|
@@ -96,7 +96,7 @@ def google_credentials(bucket = ''):
|
|
|
96
96
|
|
|
97
97
|
AWS_CREDENTIALS_CACHE:CredentialCacheType = defaultdict(dict)
|
|
98
98
|
aws_credentials_path = secretpath('aws-secret.json')
|
|
99
|
-
def aws_credentials(bucket = '', service = 'aws'):
|
|
99
|
+
def aws_credentials(bucket = '', service = 'aws', skip_files=False):
|
|
100
100
|
global AWS_CREDENTIALS_CACHE
|
|
101
101
|
|
|
102
102
|
if service == 's3':
|
|
@@ -115,12 +115,13 @@ def aws_credentials(bucket = '', service = 'aws'):
|
|
|
115
115
|
paths = [ secretpath('{}-{}-secret.json'.format(bucket, service)) ] + paths
|
|
116
116
|
|
|
117
117
|
aws_credentials = {}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
118
|
+
if not skip_files:
|
|
119
|
+
aws_credentials_path = secretpath(default_file_path)
|
|
120
|
+
for aws_credentials_path in paths:
|
|
121
|
+
if os.path.exists(aws_credentials_path):
|
|
122
|
+
with open(aws_credentials_path, 'r') as f:
|
|
123
|
+
aws_credentials = json.loads(f.read())
|
|
124
|
+
break
|
|
124
125
|
|
|
125
126
|
if not aws_credentials:
|
|
126
127
|
# did not find any secret json file, will try to find it in environment variables
|
|
@@ -128,6 +129,7 @@ def aws_credentials(bucket = '', service = 'aws'):
|
|
|
128
129
|
aws_credentials = {
|
|
129
130
|
'AWS_ACCESS_KEY_ID': os.environ['AWS_ACCESS_KEY_ID'],
|
|
130
131
|
'AWS_SECRET_ACCESS_KEY': os.environ['AWS_SECRET_ACCESS_KEY'],
|
|
132
|
+
'AWS_SESSION_TOKEN': os.environ['AWS_SESSION_TOKEN'],
|
|
131
133
|
}
|
|
132
134
|
if 'AWS_DEFAULT_REGION' in os.environ:
|
|
133
135
|
aws_credentials['AWS_DEFAULT_REGION'] = os.environ['AWS_DEFAULT_REGION']
|
cloudfiles_cli/cloudfiles_cli.py
CHANGED
|
@@ -172,11 +172,12 @@ def get_mfp(path, recursive):
|
|
|
172
172
|
@click.option('--progress', is_flag=True, default=False, help="Show transfer progress.", show_default=True)
|
|
173
173
|
@click.option('-b', '--block-size', default=128, help="Number of files to download at a time.", show_default=True)
|
|
174
174
|
@click.option('--part-bytes', default=int(1e8), help="Composite upload threshold in bytes. Splits a file into pieces for some cloud services like gs and s3.", show_default=True)
|
|
175
|
+
@click.option('--no-sign-request', is_flag=True, default=False, help="Use s3 in anonymous mode (don't sign requests) for the source.", show_default=True)
|
|
175
176
|
@click.pass_context
|
|
176
177
|
def cp(
|
|
177
178
|
ctx, source, destination,
|
|
178
179
|
recursive, compression, progress,
|
|
179
|
-
block_size, part_bytes
|
|
180
|
+
block_size, part_bytes, no_sign_request,
|
|
180
181
|
):
|
|
181
182
|
"""
|
|
182
183
|
Copy one or more files from a source to destination.
|
|
@@ -194,9 +195,17 @@ def cp(
|
|
|
194
195
|
return
|
|
195
196
|
|
|
196
197
|
for src in source:
|
|
197
|
-
_cp_single(
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
_cp_single(
|
|
199
|
+
ctx, src, destination, recursive,
|
|
200
|
+
compression, progress, block_size,
|
|
201
|
+
part_bytes, no_sign_request
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def _cp_single(
|
|
205
|
+
ctx, source, destination, recursive,
|
|
206
|
+
compression, progress, block_size,
|
|
207
|
+
part_bytes, no_sign_request
|
|
208
|
+
):
|
|
200
209
|
use_stdin = (source == '-')
|
|
201
210
|
use_stdout = (destination == '-')
|
|
202
211
|
|
|
@@ -243,7 +252,9 @@ def _cp_single(ctx, source, destination, recursive, compression, progress, block
|
|
|
243
252
|
xferpaths = [ x.replace(prefix, "") for x in xferpaths ]
|
|
244
253
|
srcpath = cloudpathjoin(srcpath, prefix)
|
|
245
254
|
elif many:
|
|
246
|
-
xferpaths = CloudFiles(
|
|
255
|
+
xferpaths = CloudFiles(
|
|
256
|
+
srcpath, no_sign_request=no_sign_request
|
|
257
|
+
).list(prefix=prefix, flat=flat)
|
|
247
258
|
|
|
248
259
|
destpath = ndest
|
|
249
260
|
if isinstance(xferpaths, str):
|
|
@@ -260,7 +271,7 @@ def _cp_single(ctx, source, destination, recursive, compression, progress, block
|
|
|
260
271
|
|
|
261
272
|
if not isinstance(xferpaths, str):
|
|
262
273
|
if parallel == 1:
|
|
263
|
-
_cp(srcpath, destpath, compression, progress, block_size, part_bytes, xferpaths)
|
|
274
|
+
_cp(srcpath, destpath, compression, progress, block_size, part_bytes, no_sign_request, xferpaths)
|
|
264
275
|
return
|
|
265
276
|
|
|
266
277
|
total = None
|
|
@@ -270,16 +281,16 @@ def _cp_single(ctx, source, destination, recursive, compression, progress, block
|
|
|
270
281
|
pass
|
|
271
282
|
|
|
272
283
|
if use_stdout:
|
|
273
|
-
fn = partial(_cp_stdout, srcpath)
|
|
284
|
+
fn = partial(_cp_stdout, no_sign_request, srcpath)
|
|
274
285
|
else:
|
|
275
|
-
fn = partial(_cp, srcpath, destpath, compression, False, block_size, part_bytes)
|
|
286
|
+
fn = partial(_cp, srcpath, destpath, compression, False, block_size, part_bytes, no_sign_request)
|
|
276
287
|
|
|
277
288
|
with tqdm(desc="Transferring", total=total, disable=(not progress)) as pbar:
|
|
278
289
|
with pathos.pools.ProcessPool(parallel) as executor:
|
|
279
290
|
for _ in executor.imap(fn, sip(xferpaths, block_size)):
|
|
280
291
|
pbar.update(block_size)
|
|
281
292
|
else:
|
|
282
|
-
cfsrc = CloudFiles(srcpath, progress=progress)
|
|
293
|
+
cfsrc = CloudFiles(srcpath, progress=progress, no_sign_request=no_sign_request)
|
|
283
294
|
if not cfsrc.exists(xferpaths):
|
|
284
295
|
print(f"cloudfiles: source path not found: {cfsrc.abspath(xferpaths).replace('file://','')}")
|
|
285
296
|
return
|
|
@@ -288,7 +299,11 @@ def _cp_single(ctx, source, destination, recursive, compression, progress, block
|
|
|
288
299
|
_cp_stdout(srcpath, xferpaths)
|
|
289
300
|
return
|
|
290
301
|
|
|
291
|
-
cfdest = CloudFiles(
|
|
302
|
+
cfdest = CloudFiles(
|
|
303
|
+
destpath,
|
|
304
|
+
progress=progress,
|
|
305
|
+
composite_upload_threshold=part_bytes,
|
|
306
|
+
)
|
|
292
307
|
|
|
293
308
|
if isdestdir:
|
|
294
309
|
new_path = os.path.basename(nsrc)
|
|
@@ -300,17 +315,17 @@ def _cp_single(ctx, source, destination, recursive, compression, progress, block
|
|
|
300
315
|
"dest_path": new_path,
|
|
301
316
|
}], reencode=compression)
|
|
302
317
|
|
|
303
|
-
def _cp(src, dst, compression, progress, block_size, part_bytes, paths):
|
|
304
|
-
cfsrc = CloudFiles(src, progress=progress, composite_upload_threshold=part_bytes)
|
|
318
|
+
def _cp(src, dst, compression, progress, block_size, part_bytes, no_sign_request, paths):
|
|
319
|
+
cfsrc = CloudFiles(src, progress=progress, composite_upload_threshold=part_bytes, no_sign_request=no_sign_request)
|
|
305
320
|
cfdest = CloudFiles(dst, progress=progress, composite_upload_threshold=part_bytes)
|
|
306
321
|
cfsrc.transfer_to(
|
|
307
322
|
cfdest, paths=paths,
|
|
308
323
|
reencode=compression, block_size=block_size
|
|
309
324
|
)
|
|
310
325
|
|
|
311
|
-
def _cp_stdout(src, paths):
|
|
326
|
+
def _cp_stdout(src, no_sign_request, paths):
|
|
312
327
|
paths = toiter(paths)
|
|
313
|
-
cf = CloudFiles(src, progress=False)
|
|
328
|
+
cf = CloudFiles(src, progress=False, no_sign_request=no_sign_request)
|
|
314
329
|
for res in cf.get(paths):
|
|
315
330
|
content = res["content"].decode("utf8")
|
|
316
331
|
sys.stdout.write(content)
|
|
@@ -372,7 +387,8 @@ def xferexecute(db, progress, lease_msec, block_size):
|
|
|
372
387
|
@main.command()
|
|
373
388
|
@click.argument("sources", nargs=-1)
|
|
374
389
|
@click.option('-r', '--range', 'byte_range', default=None, help='Retrieve start-end bytes.')
|
|
375
|
-
|
|
390
|
+
@click.option('--no-sign-request', is_flag=True, default=False, help="Use s3 in anonymous mode (don't sign requests) for the source.", show_default=True)
|
|
391
|
+
def cat(sources, byte_range, no_sign_request):
|
|
376
392
|
"""Concatenate the contents of each input file and write to stdout."""
|
|
377
393
|
if '-' in sources and len(sources) == 1:
|
|
378
394
|
sources = sys.stdin.readlines()
|
|
@@ -386,7 +402,7 @@ def cat(sources, byte_range):
|
|
|
386
402
|
byte_range[0] = int(byte_range[0] or 0)
|
|
387
403
|
byte_range[1] = int(byte_range[1]) if byte_range[1] not in ("", None) else None
|
|
388
404
|
src = normalize_path(sources[0])
|
|
389
|
-
cf = CloudFiles(os.path.dirname(src))
|
|
405
|
+
cf = CloudFiles(os.path.dirname(src), no_sign_request=no_sign_request)
|
|
390
406
|
download = cf[os.path.basename(src), byte_range[0]:byte_range[1]]
|
|
391
407
|
if download is None:
|
|
392
408
|
print(f'cloudfiles: {src} does not exist')
|
|
@@ -397,7 +413,7 @@ def cat(sources, byte_range):
|
|
|
397
413
|
for srcs in sip(sources, 10):
|
|
398
414
|
srcs = [ normalize_path(src) for src in srcs ]
|
|
399
415
|
order = { src: i for i, src in enumerate(srcs) }
|
|
400
|
-
files = cloudfiles.dl(srcs)
|
|
416
|
+
files = cloudfiles.dl(srcs, no_sign_request=no_sign_request)
|
|
401
417
|
output = [ None for _ in range(len(srcs)) ]
|
|
402
418
|
for res in files:
|
|
403
419
|
if res["content"] is None:
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
cloudfiles/__init__.py,sha256=pLB4CcV2l3Jgv_ni1520Np1pfzFj8Cpr87vNxFT3rNI,493
|
|
2
|
-
cloudfiles/buckets.py,sha256=eRAYdDfvVpNyJyK5ryDRMwgNJUeEuFBJ6doWU2JkAcA,74
|
|
3
|
-
cloudfiles/cloudfiles.py,sha256=cVGgN_07W8_w6KLBl8Y8p5BPgWd_8tfaBYxgeR2pfY0,43012
|
|
4
|
-
cloudfiles/compression.py,sha256=pqYdpu5vfFv-094BpfZ2pgRjVu7ESM9pAZC09P6E8bY,6150
|
|
5
|
-
cloudfiles/connectionpools.py,sha256=bj-9sBlnc3Hc_KLcKFh-Tpm32VEceiIPO6EJPIv55FA,4461
|
|
6
|
-
cloudfiles/exceptions.py,sha256=H2IcMlZoy2Bsn-6wCPwyLDjg66LZCyxtcf3s_p21FDw,770
|
|
7
|
-
cloudfiles/gcs.py,sha256=_njJ7TpqwrHCjPHRGkBN5alCrCWKM2m9qdy5DhxMZ7U,3718
|
|
8
|
-
cloudfiles/interfaces.py,sha256=YnRhF46yUBWSU9FZzBbMyY3Q7I0YCGfpLW3x7J8v74Q,33447
|
|
9
|
-
cloudfiles/lib.py,sha256=fEqL5APu_WQhl2yxqQbwE7msHdu7U8pstAJw6LgoKO0,5142
|
|
10
|
-
cloudfiles/paths.py,sha256=wKRfGwek9p5LTERtwUp5ljOl8tx08IMqY_A0CyZSqHA,9930
|
|
11
|
-
cloudfiles/resumable_tools.py,sha256=pK-VcoPjQ2BjGjvlvH4dDCBf6lNsqHG-weiBgxVFbzA,5838
|
|
12
|
-
cloudfiles/scheduler.py,sha256=DqDANmOpB3NdzFgJDNMMibRIkCrXQqIh2XGL8GWoc9c,3668
|
|
13
|
-
cloudfiles/secrets.py,sha256=Odmb3lfqT5cbqQfMwM-0MU3-gH-td8Mp8Yj4TPNcfgQ,4805
|
|
14
|
-
cloudfiles/threaded_queue.py,sha256=Nl4vfXhQ6nDLF8PZpSSBpww0M2zWtcd4DLs3W3BArBw,7082
|
|
15
|
-
cloudfiles/typing.py,sha256=f3ZYkNfN9poxhGu5j-P0KCxjCCqSn9HAg5KiIPkjnCg,416
|
|
16
|
-
cloudfiles_cli/LICENSE,sha256=Jna4xYE8CCQmaxjr5Fs-wmUBnIQJ1DGcNn9MMjbkprk,1538
|
|
17
|
-
cloudfiles_cli/__init__.py,sha256=Wftt3R3F21QsHtWqx49ODuqT9zcSr0em7wk48kcH0WM,29
|
|
18
|
-
cloudfiles_cli/cloudfiles_cli.py,sha256=98F7dexiVaf6M_I-k0zPDStnq155pXMqb5Jsk0UVvBw,27715
|
|
19
|
-
cloud_files-4.21.1.dist-info/AUTHORS,sha256=Vz2od9ULDs4fjsnR9D4v9NZphUeXtO8FzLHTltRxdog,221
|
|
20
|
-
cloud_files-4.21.1.dist-info/LICENSE,sha256=Jna4xYE8CCQmaxjr5Fs-wmUBnIQJ1DGcNn9MMjbkprk,1538
|
|
21
|
-
cloud_files-4.21.1.dist-info/METADATA,sha256=wpnNlgZ18JQydHbE9IhmWEODex-HwZWHCzQRDQnVywI,26818
|
|
22
|
-
cloud_files-4.21.1.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92
|
|
23
|
-
cloud_files-4.21.1.dist-info/entry_points.txt,sha256=tXTzJAamPFmjZkCnbMtL8iKUjUwmWCLfl9ekxUwZhHA,52
|
|
24
|
-
cloud_files-4.21.1.dist-info/pbr.json,sha256=Wm6fkuAec-aiStYRYSPJvWb4C6LWRr8pwVAiFa6Fi00,46
|
|
25
|
-
cloud_files-4.21.1.dist-info/top_level.txt,sha256=xPyrST3okJbsmdCF5IC2gYAVxg_aD5AYVTnNo8UuoZU,26
|
|
26
|
-
cloud_files-4.21.1.dist-info/RECORD,,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"git_version": "6b74d88", "is_release": true}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|