comparison planemo/lib/python3.7/site-packages/boto/s3/multipart.py @ 0:d30785e31577 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:18:57 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:d30785e31577
1 # Copyright (c) 2006-2012 Mitch Garnaat http://garnaat.org/
2 # Copyright (c) 2012 Amazon.com, Inc. or its affiliates.
3 # Copyright (c) 2010, Eucalyptus Systems, Inc.
4 # All Rights Reserved
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a
7 # copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish, dis-
10 # tribute, sublicense, and/or sell copies of the Software, and to permit
11 # persons to whom the Software is furnished to do so, subject to the fol-
12 # lowing conditions:
13 #
14 # The above copyright notice and this permission notice shall be included
15 # in all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
19 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
20 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24
25 from boto.s3 import user
26 from boto.s3 import key
27 from boto import handler
28 import xml.sax
29
30
31 class CompleteMultiPartUpload(object):
32 """
33 Represents a completed MultiPart Upload. Contains the
34 following useful attributes:
35
36 * location - The URI of the completed upload
37 * bucket_name - The name of the bucket in which the upload
38 is contained
39 * key_name - The name of the new, completed key
40 * etag - The MD5 hash of the completed, combined upload
41 * version_id - The version_id of the completed upload
42 * encrypted - The value of the encryption header
43 """
44
45 def __init__(self, bucket=None):
46 self.bucket = bucket
47 self.location = None
48 self.bucket_name = None
49 self.key_name = None
50 self.etag = None
51 self.version_id = None
52 self.encrypted = None
53
54 def __repr__(self):
55 return '<CompleteMultiPartUpload: %s.%s>' % (self.bucket_name,
56 self.key_name)
57
58 def startElement(self, name, attrs, connection):
59 return None
60
61 def endElement(self, name, value, connection):
62 if name == 'Location':
63 self.location = value
64 elif name == 'Bucket':
65 self.bucket_name = value
66 elif name == 'Key':
67 self.key_name = value
68 elif name == 'ETag':
69 self.etag = value
70 else:
71 setattr(self, name, value)
72
73
74 class Part(object):
75 """
76 Represents a single part in a MultiPart upload.
77 Attributes include:
78
79 * part_number - The integer part number
80 * last_modified - The last modified date of this part
81 * etag - The MD5 hash of this part
82 * size - The size, in bytes, of this part
83 """
84
85 def __init__(self, bucket=None):
86 self.bucket = bucket
87 self.part_number = None
88 self.last_modified = None
89 self.etag = None
90 self.size = None
91
92 def __repr__(self):
93 if isinstance(self.part_number, int):
94 return '<Part %d>' % self.part_number
95 else:
96 return '<Part %s>' % None
97
98 def startElement(self, name, attrs, connection):
99 return None
100
101 def endElement(self, name, value, connection):
102 if name == 'PartNumber':
103 self.part_number = int(value)
104 elif name == 'LastModified':
105 self.last_modified = value
106 elif name == 'ETag':
107 self.etag = value
108 elif name == 'Size':
109 self.size = int(value)
110 else:
111 setattr(self, name, value)
112
113
114 def part_lister(mpupload, part_number_marker=None):
115 """
116 A generator function for listing parts of a multipart upload.
117 """
118 more_results = True
119 part = None
120 while more_results:
121 parts = mpupload.get_all_parts(None, part_number_marker)
122 for part in parts:
123 yield part
124 part_number_marker = mpupload.next_part_number_marker
125 more_results = mpupload.is_truncated
126
127
128 class MultiPartUpload(object):
129 """
130 Represents a MultiPart Upload operation.
131 """
132
133 def __init__(self, bucket=None):
134 self.bucket = bucket
135 self.bucket_name = None
136 self.key_name = None
137 self.id = id
138 self.initiator = None
139 self.owner = None
140 self.storage_class = None
141 self.initiated = None
142 self.part_number_marker = None
143 self.next_part_number_marker = None
144 self.max_parts = None
145 self.is_truncated = False
146 self._parts = None
147
148 def __repr__(self):
149 return '<MultiPartUpload %s>' % self.key_name
150
151 def __iter__(self):
152 return part_lister(self)
153
154 def to_xml(self):
155 s = '<CompleteMultipartUpload>\n'
156 for part in self:
157 s += ' <Part>\n'
158 s += ' <PartNumber>%d</PartNumber>\n' % part.part_number
159 s += ' <ETag>%s</ETag>\n' % part.etag
160 s += ' </Part>\n'
161 s += '</CompleteMultipartUpload>'
162 return s
163
164 def startElement(self, name, attrs, connection):
165 if name == 'Initiator':
166 self.initiator = user.User(self)
167 return self.initiator
168 elif name == 'Owner':
169 self.owner = user.User(self)
170 return self.owner
171 elif name == 'Part':
172 part = Part(self.bucket)
173 self._parts.append(part)
174 return part
175 return None
176
177 def endElement(self, name, value, connection):
178 if name == 'Bucket':
179 self.bucket_name = value
180 elif name == 'Key':
181 self.key_name = value
182 elif name == 'UploadId':
183 self.id = value
184 elif name == 'StorageClass':
185 self.storage_class = value
186 elif name == 'PartNumberMarker':
187 self.part_number_marker = value
188 elif name == 'NextPartNumberMarker':
189 self.next_part_number_marker = value
190 elif name == 'MaxParts':
191 self.max_parts = int(value)
192 elif name == 'IsTruncated':
193 if value == 'true':
194 self.is_truncated = True
195 else:
196 self.is_truncated = False
197 elif name == 'Initiated':
198 self.initiated = value
199 else:
200 setattr(self, name, value)
201
202 def get_all_parts(self, max_parts=None, part_number_marker=None,
203 encoding_type=None):
204 """
205 Return the uploaded parts of this MultiPart Upload. This is
206 a lower-level method that requires you to manually page through
207 results. To simplify this process, you can just use the
208 object itself as an iterator and it will automatically handle
209 all of the paging with S3.
210 """
211 self._parts = []
212 query_args = 'uploadId=%s' % self.id
213 if max_parts:
214 query_args += '&max-parts=%d' % max_parts
215 if part_number_marker:
216 query_args += '&part-number-marker=%s' % part_number_marker
217 if encoding_type:
218 query_args += '&encoding-type=%s' % encoding_type
219 response = self.bucket.connection.make_request('GET', self.bucket.name,
220 self.key_name,
221 query_args=query_args)
222 body = response.read()
223 if response.status == 200:
224 h = handler.XmlHandler(self, self)
225 xml.sax.parseString(body, h)
226 return self._parts
227
228 def upload_part_from_file(self, fp, part_num, headers=None, replace=True,
229 cb=None, num_cb=10, md5=None, size=None):
230 """
231 Upload another part of this MultiPart Upload.
232
233 .. note::
234
235 After you initiate multipart upload and upload one or more parts,
236 you must either complete or abort multipart upload in order to stop
237 getting charged for storage of the uploaded parts. Only after you
238 either complete or abort multipart upload, Amazon S3 frees up the
239 parts storage and stops charging you for the parts storage.
240
241 :type fp: file
242 :param fp: The file object you want to upload.
243
244 :type part_num: int
245 :param part_num: The number of this part.
246
247 The other parameters are exactly as defined for the
248 :class:`boto.s3.key.Key` set_contents_from_file method.
249
250 :rtype: :class:`boto.s3.key.Key` or subclass
251 :returns: The uploaded part containing the etag.
252 """
253 if part_num < 1:
254 raise ValueError('Part numbers must be greater than zero')
255 query_args = 'uploadId=%s&partNumber=%d' % (self.id, part_num)
256 key = self.bucket.new_key(self.key_name)
257 key.set_contents_from_file(fp, headers=headers, replace=replace,
258 cb=cb, num_cb=num_cb, md5=md5,
259 reduced_redundancy=False,
260 query_args=query_args, size=size)
261 return key
262
263 def copy_part_from_key(self, src_bucket_name, src_key_name, part_num,
264 start=None, end=None, src_version_id=None,
265 headers=None):
266 """
267 Copy another part of this MultiPart Upload.
268
269 :type src_bucket_name: string
270 :param src_bucket_name: Name of the bucket containing the source key
271
272 :type src_key_name: string
273 :param src_key_name: Name of the source key
274
275 :type part_num: int
276 :param part_num: The number of this part.
277
278 :type start: int
279 :param start: Zero-based byte offset to start copying from
280
281 :type end: int
282 :param end: Zero-based byte offset to copy to
283
284 :type src_version_id: string
285 :param src_version_id: version_id of source object to copy from
286
287 :type headers: dict
288 :param headers: Any headers to pass along in the request
289 """
290 if part_num < 1:
291 raise ValueError('Part numbers must be greater than zero')
292 query_args = 'uploadId=%s&partNumber=%d' % (self.id, part_num)
293 if start is not None and end is not None:
294 rng = 'bytes=%s-%s' % (start, end)
295 provider = self.bucket.connection.provider
296 if headers is None:
297 headers = {}
298 else:
299 headers = headers.copy()
300 headers[provider.copy_source_range_header] = rng
301 return self.bucket.copy_key(self.key_name, src_bucket_name,
302 src_key_name,
303 src_version_id=src_version_id,
304 storage_class=None,
305 headers=headers,
306 query_args=query_args)
307
308 def complete_upload(self):
309 """
310 Complete the MultiPart Upload operation. This method should
311 be called when all parts of the file have been successfully
312 uploaded to S3.
313
314 :rtype: :class:`boto.s3.multipart.CompletedMultiPartUpload`
315 :returns: An object representing the completed upload.
316 """
317 xml = self.to_xml()
318 return self.bucket.complete_multipart_upload(self.key_name,
319 self.id, xml)
320
321 def cancel_upload(self):
322 """
323 Cancels a MultiPart Upload operation. The storage consumed by
324 any previously uploaded parts will be freed. However, if any
325 part uploads are currently in progress, those part uploads
326 might or might not succeed. As a result, it might be necessary
327 to abort a given multipart upload multiple times in order to
328 completely free all storage consumed by all parts.
329 """
330 self.bucket.cancel_multipart_upload(self.key_name, self.id)