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.
@@ -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.21.1
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
  [![PyPI version](https://badge.fury.io/py/cloud-files.svg)](https://badge.fury.io/py/cloud-files) [![Test Suite](https://github.com/seung-lab/cloud-files/workflows/Test%20Suite/badge.svg)](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,,
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  cloudfiles = cloudfiles_cli:main
3
-
@@ -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.get("parallel", None)
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, cf_dest:Any, paths:Any = None, # recursive CloudFiles not supported as type
945
- block_size:int = 64, reencode:Optional[str] = None
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, cf_src:Any, paths:Any = None, # recursive CloudFiles not supported as type
989
- block_size:int = 64, reencode:Optional[str] = None
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(cf_src, self, paths, total, pbar, block_size)
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(cf_src, self, paths, total, pbar, block_size)
1077
+ self.__transfer_cloud_internal(
1078
+ cf_src, self, paths,
1079
+ total, pbar, block_size
1080
+ )
1059
1081
  else:
1060
- self.__transfer_general(cf_src, self, paths, total, pbar, block_size, reencode)
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(renameiter(), raw=True, progress=False, compress=reencode)
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))
@@ -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__(self, path, secrets=None, request_payer=None, composite_upload_threshold=int(1e8), **kwargs):
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
- aws_credentials_path = secretpath(default_file_path)
119
- for aws_credentials_path in paths:
120
- if os.path.exists(aws_credentials_path):
121
- with open(aws_credentials_path, 'r') as f:
122
- aws_credentials = json.loads(f.read())
123
- break
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']
@@ -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(ctx, src, destination, recursive, compression, progress, block_size, part_bytes)
198
-
199
- def _cp_single(ctx, source, destination, recursive, compression, progress, block_size, part_bytes):
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(srcpath).list(prefix=prefix, flat=flat)
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(destpath, progress=progress, composite_upload_threshold=part_bytes)
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
- def cat(sources, byte_range):
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}