B 劇cpqã@sldZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z ddlmZddlmZddlZddlmZmZdZdZGd d „d ejƒZe e¡Ze eƒ¡d Ze ƒZ!d%d d„Z"dd„Z#dd„Z$Gdd„de%ƒZ&Gdd„dƒZ'Gdd„dƒZ(Gdd„dƒZ)Gdd„dƒZ*Gdd„dej+ƒZ,Gdd „d ƒZ-Gd!d"„d"ƒZ.Gd#d$„d$ƒZ/dS)&a®Abstractions over S3's upload/download operations. This module provides high level abstractions for efficient uploads/downloads. It handles several things for the user: * Automatically switching to multipart transfers when a file is over a specific size threshold * Uploading/downloading a file in parallel * Throttling based on max bandwidth * Progress callbacks to monitor transfers * Retries. While botocore handles retries for streaming uploads, it is not possible for it to handle retries for streaming downloads. This module handles retries for both cases so you don't need to implement any retry logic yourself. This module has a reasonable set of defaults. It also allows you to configure many aspects of the transfer process including: * Multipart threshold size * Max parallel downloads * Max bandwidth * Socket timeouts * Retry amounts There is no support for s3->s3 multipart copies at this time. .. _ref_s3transfer_usage: Usage ===== The simplest way to use this module is: .. code-block:: python client = boto3.client('s3', 'us-west-2') transfer = S3Transfer(client) # Upload /tmp/myfile to s3://bucket/key transfer.upload_file('/tmp/myfile', 'bucket', 'key') # Download s3://bucket/key to /tmp/myfile transfer.download_file('bucket', 'key', '/tmp/myfile') The ``upload_file`` and ``download_file`` methods also accept ``**kwargs``, which will be forwarded through to the corresponding client operation. Here are a few examples using ``upload_file``:: # Making the object public transfer.upload_file('/tmp/myfile', 'bucket', 'key', extra_args={'ACL': 'public-read'}) # Setting metadata transfer.upload_file('/tmp/myfile', 'bucket', 'key', extra_args={'Metadata': {'a': 'b', 'c': 'd'}}) # Setting content type transfer.upload_file('/tmp/myfile.json', 'bucket', 'key', extra_args={'ContentType': "application/json"}) The ``S3Transfer`` class also supports progress callbacks so you can provide transfer progress to users. Both the ``upload_file`` and ``download_file`` methods take an optional ``callback`` parameter. Here's an example of how to print a simple progress percentage to the user: .. code-block:: python class ProgressPercentage(object): def __init__(self, filename): self._filename = filename self._size = float(os.path.getsize(filename)) self._seen_so_far = 0 self._lock = threading.Lock() def __call__(self, bytes_amount): # To simplify we'll assume this is hooked up # to a single filename. with self._lock: self._seen_so_far += bytes_amount percentage = (self._seen_so_far / self._size) * 100 sys.stdout.write( " %s %s / %s (%.2f%%)" % (self._filename, self._seen_so_far, self._size, percentage)) sys.stdout.flush() transfer = S3Transfer(boto3.client('s3', 'us-west-2')) # Upload /tmp/myfile to s3://bucket/key and print upload progress. transfer.upload_file('/tmp/myfile', 'bucket', 'key', callback=ProgressPercentage('/tmp/myfile')) You can also provide a TransferConfig object to the S3Transfer object that gives you more fine grained control over the transfer. For example: .. code-block:: python client = boto3.client('s3', 'us-west-2') config = TransferConfig( multipart_threshold=8 * 1024 * 1024, max_concurrency=10, num_download_attempts=10, ) transfer = S3Transfer(client, config) transfer.upload_file('/tmp/foo', 'bucket', 'key') éN)Úsix)ÚIncompleteReadError)ÚReadTimeoutError)ÚRetriesExceededErrorÚS3UploadFailedErrorzAmazon Web Servicesz0.6.0c@seZdZdd„ZdS)Ú NullHandlercCsdS)N©)ÚselfÚrecordrrún/private/var/folders/8c/hx9_v10d5x38qmnzt13b7b8j1k3n5b/T/pip-target-x6xd5gna/lib/python/s3transfer/__init__.pyÚemit—szNullHandler.emitN)Ú__name__Ú __module__Ú __qualname__r rrrr r–sriécCsd dd„t|ƒDƒ¡S)NÚcss|]}t tj¡VqdS)N)ÚrandomÚchoiceÚstringÚ hexdigits)Ú.0Ú_rrr ú £sz(random_file_extension..)ÚjoinÚrange)Z num_digitsrrr Úrandom_file_extension¢srcKs"|dkrt|jdƒr|j ¡dS)N)Ú PutObjectÚ UploadPartÚdisable_callback)ÚhasattrÚbodyr)ÚrequestÚoperation_nameÚkwargsrrr Údisable_upload_callbacks¦s  r$cKs"|dkrt|jdƒr|j ¡dS)N)rrÚenable_callback)rr r%)r!r"r#rrr Úenable_upload_callbacks­s  r&c@s eZdZdS)ÚQueueShutdownErrorN)r rrrrrr r'´sr'c@s~eZdZddd„Zeddd„ƒZdd„Zdd d „Zd d „Zd d„Z dd„Z dd„Z dd„Z dd„Z dd„Zdd„Zdd„ZdS) Ú ReadFileChunkNTcCsF||_||_|j|j|||d�|_|j |j¡d|_||_||_dS)a‚ Given a file object shown below: |___________________________________________________| 0 | | full_file_size |----chunk_size---| start_byte :type fileobj: file :param fileobj: File like object :type start_byte: int :param start_byte: The first byte from which to start reading. :type chunk_size: int :param chunk_size: The max chunk size to read. Trying to read pass the end of the chunk size will behave like you've reached the end of the file. :type full_file_size: int :param full_file_size: The entire content length associated with ``fileobj``. :type callback: function(amount_read) :param callback: Called whenever data is read from this object. )Úrequested_sizeÚ start_byteÚactual_file_sizerN)Ú_fileobjÚ _start_byteÚ_calculate_file_sizeÚ_sizeÚseekÚ _amount_readÚ _callbackÚ_callback_enabled)r Úfileobjr*Ú chunk_sizeZfull_file_sizeÚcallbackr%rrr Ú__init__¹s% zReadFileChunk.__init__cCs,t|dƒ}t | ¡¡j}|||||||ƒS)aWConvenience factory function to create from a filename. :type start_byte: int :param start_byte: The first byte from which to start reading. :type chunk_size: int :param chunk_size: The max chunk size to read. Trying to read pass the end of the chunk size will behave like you've reached the end of the file. :type full_file_size: int :param full_file_size: The entire content length associated with ``fileobj``. :type callback: function(amount_read) :param callback: Called whenever data is read from this object. :type enable_callback: bool :param enable_callback: Indicate whether to invoke callback during read() calls. :rtype: ``ReadFileChunk`` :return: A new instance of ``ReadFileChunk`` Úrb)ÚopenÚosÚfstatÚfilenoÚst_size)ÚclsÚfilenamer*r5r6r%ÚfÚ file_sizerrr Ú from_filenameës" zReadFileChunk.from_filenamecCs||}t||ƒS)N)Úmin)r r4r)r*r+Zmax_chunk_sizerrr r.sz"ReadFileChunk._calculate_file_sizecCsh|dkr|j|j}nt|j|j|ƒ}|j |¡}|jt|ƒ7_|jdk rd|jrd| t|ƒ¡|S)N)r/r1rCr,ÚreadÚlenr2r3)r ÚamountZamount_to_readÚdatarrr rDs zReadFileChunk.readcCs d|_dS)NT)r3)r rrr r%$szReadFileChunk.enable_callbackcCs d|_dS)NF)r3)r rrr r'szReadFileChunk.disable_callbackcCs<|j |j|¡|jdk r2|jr2| ||j¡||_dS)N)r,r0r-r2r3r1)r Úwhererrr r0*szReadFileChunk.seekcCs|j ¡dS)N)r,Úclose)r rrr rI1szReadFileChunk.closecCs|jS)N)r1)r rrr Útell4szReadFileChunk.tellcCs|jS)N)r/)r rrr Ú__len__7szReadFileChunk.__len__cCs|S)Nr)r rrr Ú __enter__?szReadFileChunk.__enter__cOs | ¡dS)N)rI)r Úargsr#rrr Ú__exit__BszReadFileChunk.__exit__cCstgƒS)N)Úiter)r rrr Ú__iter__EszReadFileChunk.__iter__)NT)NT)N)r rrr7Ú classmethodrBr.rDr%rr0rIrJrKrLrNrPrrrr r(¸s  + ! r(c@s"eZdZdZddd„Zdd„ZdS)ÚStreamReaderProgresszióz5MultipartDownloader._download_range..rÉzCRetrying exception caught (%s), retrying request, (attempt %s / %s)T)ryz$EXITING _download_range for part: %s)rÄrjÚnum_download_attemptsrr}r~riÚ get_objectrRrOr­r©rEÚsocketÚtimeoutr_rrr)r r€rtr?r“r”r6rÂrÃÚ max_attemptsÚlast_exceptionÚir�Z current_indexÚchunkr„r)rÆrÇr r¾SsD     z#MultipartDownloader._download_rangec Cs¤|j |d¡�Œ}x„|j ¡}|tkr2t d¡dSy |\}}| |¡| |¡Wqt k r�}z tjd|dd�|j  ¡‚Wdd}~XYqXqWWdQRXdS)NÚwbzCShutdown sentinel received in IO handler, shutting down IO handler.z!Caught exception in IO thread: %sT)ry) rkr9r­ÚgetrÀr}r~r0Úwriter|r¨)r r?r@ÚtaskÚoffsetrGr„rrr r²‚s$   z&MultipartDownloader._perform_io_writes)N) r rrrœr�ržr7r¹rµr°rÄr¾r²rrrr r«s  /r«c@s(eZdZdeddeddfdd„ZdS)ÚTransferConfigré éédcCs"||_||_||_||_||_dS)N)Úmultipart_thresholdr�rˆrÊr¬)r rÛr�rˆrÊr¬rrr r7œs zTransferConfig.__init__N)r rrÚMBr7rrrr r×›s r×c@s¦eZdZdddddgZdddd d d d d dddddddddddddgZd.dd„Zd/dd„Zdd„Zd0dd„Zd d!„Z d"d#„Z d$d%„Z d&d'„Z d(d)„Z d*d+„Zd,d-„ZdS)1Ú S3TransferZ VersionIdrfrergrhZACLÚ CacheControlZContentDispositionZContentEncodingZContentLanguageZ ContentTypeZExpiresZGrantFullControlZ GrantReadZ GrantReadACPZ GrantWriteACLZMetadataZServerSideEncryptionZ StorageClassZ SSEKMSKeyIdZSSEKMSEncryptionContextZTaggingNcCs2||_|dkrtƒ}||_|dkr(tƒ}||_dS)N)rir×rjrWÚ_osutil)r rmrnrorrr r7ÍszS3Transfer.__init__cCs‚|dkr i}| ||j¡|jjj}|jdtdd�|jdtdd�|j   |¡|j j krl|  |||||¡n| |||||¡dS)zµUpload a file to an S3 object. Variants have also been injected into S3 client, Bucket and Object. You don't have to use S3Transfer.upload_file() directly. Nzrequest-created.s3zs3upload-callback-disable)Ú unique_idzs3upload-callback-enable)Ú_validate_all_known_argsÚALLOWED_UPLOAD_ARGSriÚmetaÚeventsZregister_firstr$Z register_lastr&rßrZrjrÛÚ_multipart_uploadÚ _put_object)r r?r€rtr6rsrärrr r…Ös    zS3Transfer.upload_filec CsJ|jj}||d|j |¡|d�� }|jjf|||dœ|—ŽWdQRXdS)Nr)r6)rvrwr˜)rßr\rZriZ put_object)r r?r€rtr6rsršr rrr ræôs zS3Transfer._put_objectcCs–|dkr i}| ||j¡| |||¡}|tjtƒ}y| ||||||¡Wn2tk r‚tj d|dd�|j   |¡‚YnX|j   ||¡dS)z¹Download an S3 object to a file. Variants have also been injected into S3 client, Bucket and Object. You don't have to use S3Transfer.download_file() directly. Nzs(zS3Transfer._get_objectc sj|jjf||dœ|—Ž}t|d|ƒ‰|j |d¡�,}x$t‡fdd„dƒD]}| |¡qJWWdQRXdS)N)rvrwr˜rÒcs ˆ d¡S)Ni )rDr)rÇrr rÈarÉz+S3Transfer._do_get_object..rÉ)rirËrRrßr9rOrÔ) r r€rtr?rsr6r�r@rÑr)rÇr rñ[s zS3Transfer._do_get_objectcCs|jjf||dœ|—ŽdS)N)rvrwZ ContentLength)riZ head_object)r r€rtrsrrr rèdszS3Transfer._object_sizecCs(t|j|j|jƒ}| |||||¡dS)N)rdrirjrßr…)r r?r€rtr6rsZuploaderrrr råiszS3Transfer._multipart_upload)NN)NN)NN)r rrrçrâr7r…rær¹rêrárërìrñrèrårrrr rÝ«sJ     rÝ)r)0rVÚconcurrent.futuresrœrŽÚloggingrŠr:r¤rrÌrr¡Zbotocore.compatrZbotocore.exceptionsrZ6botocore.vendored.requests.packages.urllib3.exceptionsrZs3transfer.compatraZs3transfer.exceptionsrrÚ __author__Ú __version__ÚHandlerrÚ getLoggerr r}Ú addHandlerrÜÚobjectrÀrr$r&r|r'r(rRrWrdr¥rŸr«r×rÝrrrr Ú}sH      q"