U
    n/eKM                    @   sN  d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZmZ d dl	Z	d dl
Z
d dlmZ d dlZd dlmZ d dlmZmZmZ d dlmZmZmZmZmZmZ d dlmZ d dlZd dlZd dl Zd dl!m"Z" d d	l#m$Z$m%Z%m&Z& d d
l'm(Z( d dl)m*Z* d dl+m,Z,m-Z-m.Z.m/Z/ zd dl0m1Z1 W n e2k
rB   dZ1Y nX e3dZ4dCddZdej5krje  dZ6ej7e%eee(fZ8e1dk	re8e1f7 Z8ddddddhZ9dddddddd d!d"d#d$d%d&d'd(d)gZ:d*d+d,d-d.d/d0hZ;d*d+d,d-hZ<d1dd2d3d4Z=d5d6 Z>d7d8 Z?G d9d: d:eZ@G d;d< d<eZAG d=d> d>eZBdDd?d@ZCdEdAdBZDdS )F    N)TupleOptional)IncompleteRead)AbstractBufferedFile)infer_storage_optionstokenizesetup_logging)AsyncFileSystemAbstractAsyncStreamedFilesyncsync_wrapperFSTimeoutError_run_coros_in_chunks)_DEFAULT_CALLBACK)	AioConfig)ClientErrorHTTPClientErrorParamValidationError)ResponseParserError)translate_boto_error)S3BucketRegionCacheParamKwargsHelper_get_brangeFileExpired)ClientPayloadErrorZs3fsc                 C   s   t t| ptjd d d S )NS3FS_LOGGING_LEVEL)loggerlevel)setup_loggerr   osenviron)r    r!   -/tmp/pip-unpacked-wheel-zv_a3qq1/s3fs/core.pyr   1   s    r   r           rwarbwbabCacheControlZContentDispositionZContentEncodingZContentLanguageContentLengthContentTypeZExpiresZWebsiteRedirectLocationZServerSideEncryptionZSSECustomerAlgorithmZSSEKMSKeyIdZBucketKeyEnabledStorageClassZObjectLockModeZObjectLockRetainUntilDateZObjectLockLegalHoldStatusMetadataprivatezpublic-readzpublic-read-writezauthenticated-readzaws-exec-readzbucket-owner-readzbucket-owner-full-controlr!   )argskwargsc                   s  |d kri }t |D ]}z| ||I d H W   S  tk
r } z2|}td| ttd| d dI d H  W 5 d }~X Y q tk
r } zLtd| |}dt|krttd| d dI d H  nW Y 
 q*W 5 d }~X Y q t	k
r& } z td| |}W Y 
 q*W 5 d }~X Y qX qdt|kr|j
}|jrP|j}q>z|jjd	 I d H  W n( t	k
r } z|}W 5 d }~X Y nX t|}|d S )
NzRetryable error: %s333333?皙?   z"Client error (maybe retryable): %sZSlowDownzNonretryable error: %sz'coroutine'response)rangeS3_RETRYABLE_ERRORSr   debugasynciosleepminr   str	Exception__traceback__tb_nexttb_framef_localsr   )funcr0   r1   retriesieerrtbr!   r!   r"   _error_wrapperl   s:    .  
rH   c                 C   s   | rd| iS i S dS )zHelper to make versionId kwargs.

    Not all boto3 methods accept a None / empty versionId so dictionary expansion solves
    that problem.
    	VersionIdNr!   
version_idr!   r!   r"   version_id_kw   s    rL   c                  G   sR   t | }d|kr|d t|dkr6td|nt|dkrFdS | S dS )z4Helper to coalesce a list of version_ids down to oneN   z?Cannot coalesce version_ids where more than one are defined, {}r   )setremovelen
ValueErrorformatpop)r0   Zversion_idsr!   r!   r"   _coalesce_version_id   s    
rT   c                       sN  e Zd ZdZdZdZdZdZdZddgZ	dZ
d fdd	Zedd Zdd ZdddZdd ZeeZdd Zedd Zdd Zeeeee f dddZd d! Zd	i fd"d#ZeZeeZed$d% Zdd'd(Z ee Z!dd*d+Z"dd-d.Z#dd/d0Z$edd1d2Z% fd3d4Z&d fd5d6	Z'ee'Z(dd7d8Z)ee)Z*dd9d:Z+ee+Z,d;d< Z-ee-Z.dd=d>Z/dd?d@Z0dAdB Z1dCdD Z2ee2Z3ddEdFZ4ee4Z5ddGdHZ6ddJdKZ7e8dIfdLdMZ9e8d
fdNdOZ:ddPdQZ;ddRdSZ<ee<Z=dTdU Z>ee>Z?dVdW Z@ee@ZAi ZBddXdYZCeeCZDdZd[ ZEdd]d^ZFd_d` ZGeeGZHddadbZIeeIZJddcddZKeeKZLddfdgZMeeMZNdhdi ZOeeOZPdjdk ZQdldm ZRddodpZSddqdrZTdsdt ZUeeUZVdudv ZWeeWZXdwdx ZYdydz ZZdd{d|Z[d}d~ Z\ee\Z]dd Z^dddZ_d fdd	Z`dddZadddZbdd ZceecZddddZe  ZfS )S3FileSystemaP  
    Access S3 as if it were a file system.

    This exposes a filesystem-like API (ls, cp, open, etc.) on top of S3
    storage.

    Provide credentials either explicitly (``key=``, ``secret=``) or depend
    on boto's credential methods. See botocore documentation for more
    information. If no credentials are available, use ``anon=True``.

    Parameters
    ----------
    anon : bool (False)
        Whether to use anonymous connection (public buckets only). If False,
        uses the key/secret given, or boto's credential resolver (client_kwargs,
        environment, variables, config files, EC2 IAM server, in that order)
    endpoint_url : string (None)
        Use this endpoint_url, if specified. Needed for connecting to non-AWS
        S3 buckets. Takes precedence over `endpoint_url` in client_kwargs.
    key : string (None)
        If not anonymous, use this access key ID, if specified. Takes precedence
        over `aws_access_key_id` in client_kwargs.
    secret : string (None)
        If not anonymous, use this secret access key, if specified. Takes
        precedence over `aws_secret_access_key` in client_kwargs.
    token : string (None)
        If not anonymous, use this security token, if specified
    use_ssl : bool (True)
        Whether to use SSL in connections to S3; may be faster without, but
        insecure. If ``use_ssl`` is also set in ``client_kwargs``,
        the value set in ``client_kwargs`` will take priority.
    s3_additional_kwargs : dict of parameters that are used when calling s3 api
        methods. Typically used for things like "ServerSideEncryption".
    client_kwargs : dict of parameters for the botocore client
    requester_pays : bool (False)
        If RequesterPays buckets are supported.
    default_block_size: int (None)
        If given, the default block size value used for ``open()``, if no
        specific value is given at all time. The built-in default is 5MB.
    default_fill_cache : Bool (True)
        Whether to use cache filling with open by default. Refer to
        ``S3File.open``.
    default_cache_type : string ("readahead")
        If given, the default cache_type value used for ``open()``. Set to "none"
        if no caching is desired. See fsspec's documentation for other available
        cache_type values. Default cache_type is "readahead".
    version_aware : bool (False)
        Whether to support bucket versioning.  If enable this will require the
        user to have the necessary IAM permissions for dealing with versioned
        objects. Note that in the event that you only need to work with the
        latest version of objects in a versioned bucket, and do not need the
        VersionId for those objects, you should set ``version_aware`` to False
        for performance reasons. When set to True, filesystem instances will
        use the S3 ListObjectVersions API call to list directory contents,
        which requires listing all historical object versions.
    cache_regions : bool (False)
        Whether to cache bucket regions or not. Whenever a new bucket is used,
        it will first find out which region it belongs and then use the client
        for that region.
    asynchronous :  bool (False)
        Whether this instance is to be used from inside coroutines.
    config_kwargs : dict of parameters passed to ``botocore.client.Config``
    kwargs : other parameters for core session.
    session : aiobotocore AioSession object to be used for all connections.
         This session will be used inplace of creating a new session inside S3FileSystem.
         For example: aiobotocore.session.AioSession(profile='test_user')

    The following parameters are passed on to fsspec:

    skip_instance_cache: to control reuse of instances
    use_listings_cache, listings_expiry_time, max_paths: to control reuse of directory listings

    Examples
    --------
    >>> s3 = S3FileSystem(anon=False)  # doctest: +SKIP
    >>> s3.ls('my-bucket/')  # doctest: +SKIP
    ['my-file.txt']

    >>> with s3.open('my-bucket/my-file.txt', mode='rb') as f:  # doctest: +SKIP
    ...     print(f.read())  # doctest: +SKIP
    b'Hello, world!'
        r4     P s3Zs3a)default_block_sizeFNT	readaheadc                    s   |r|rt d|r |r t d|r(|}|r0|}|| _|| _|| _|| _|| _ | _ fdddD }t jf ||d| |	p| j	| _	|
| _
|| _|| _|pi | _|pi | _|rddini | _|pi | _|| _|| _d | _|| _d S )	Nz'Supply either key or username, not bothz#Supply secret or password, not bothc                    s    i | ]}| kr|  |qS r!   )rS   ).0kr1   r!   r"   
<dictcomp>/  s    z)S3FileSystem.__init__.<locals>.<dictcomp>)Zuse_listings_cacheZlistings_expiry_timeZ	max_paths)loopasynchronousRequestPayer	requester)KeyErrorendpoint_urlanonkeysecrettokenr1   super__init__rZ   default_fill_cachedefault_cache_typeversion_awareclient_kwargsconfig_kwargsreq_kws3_additional_kwargsuse_sslcache_regions_s3session)selfrf   re   rg   rh   ri   rs   ro   requester_paysrZ   rl   rm   rn   rp   rr   rv   usernamepasswordrt   ra   r`   r1   Zsuper_kwargs	__class__r^   r"   rk     s<    



zS3FileSystem.__init__c                 C   s&   | j d kr | jrtd|   | j S )Nz2please await ``.set_session`` before anything else)ru   ra   RuntimeErrorconnectrw   r!   r!   r"   rY   C  s
    
zS3FileSystem.s3c                 C   s   | j |j|S N)_kwargs_helperZfilter_dict__name__)rw   Z	s3_methodr1   r!   r!   r"   _filter_kwargsK  s    zS3FileSystem._filter_kwargsc                    s*   | j r |d k	r | j|I d H S | jS d S r   )rt   
_s3creatorZget_bucket_clientru   rw   bucketr!   r!   r"   get_s3N  s    zS3FileSystem.get_s3c                    s|   |   I d H  | |dI d H }t||}| }|dd  td|j|| | j	|f||}t
||| jdI d H S )NBucketBodyzCALL: %s - %s - %s)r1   rC   )set_sessionr   getgetattrcopyrS   r   r8   r   _get_s3_method_kwargsrH   rC   )rw   method
akwarglistr1   rY   Zkw2additional_kwargsr!   r!   r"   _call_s3T  s    
  zS3FileSystem._call_s3c                 O   s4   | j  }|D ]}|| q|| | ||S r   )rr   r   updater   )rw   r   r   r1   r   Zakwargsr!   r!   r"   r   b  s
    

z"S3FileSystem._get_s3_method_kwargsc                 C   sF   t | }|d}i }|dk	rBddlm} ||}d|krBd|d< |S )z
        When we have a urlpath that contains a ?versionId=

        Assume that we want to use version_aware mode for
        the filesystem.
        	url_queryNr   )parse_qsZ	versionIdTrn   )r   r   urllib.parser   )ZurlpathZurl_storage_optsr   outr   parsedr!   r!   r"   _get_kwargs_from_urlsk  s    
z"S3FileSystem._get_kwargs_from_urlsc                 C   s   t dt dt dt dg}|D ]*}||}|r(|d|df  S q(|dd}|d	 }d
}t|dkr|d }||fS )z
        This is a helper function that given an s3 path such that the path is of
        the form: bucket/key
        It will return the bucket and the key represented by the s3 path
        zT^(?P<bucket>arn:(aws).*:s3:[a-z\-0-9]*:[0-9]{12}:accesspoint[:/][^/]+)/?(?P<key>.*)$z^(?P<bucket>arn:(aws).*:s3-outposts:[a-z\-0-9]+:[0-9]{12}:outpost[/:][a-zA-Z0-9\-]{1,63}[/:](bucket|accesspoint)[/:][a-zA-Z0-9\-]{1,63})[/:]?(?P<key>.*)$z^(?P<bucket>arn:(aws).*:s3-outposts:[a-z\-0-9]+:[0-9]{12}:outpost[/:][a-zA-Z0-9\-]{1,63}[/:]bucket[/:][a-zA-Z0-9\-]{1,63})[/:]?(?P<key>.*)$zs^(?P<bucket>arn:(aws).*:s3-object-lambda:[a-z\-0-9]+:[0-9]{12}:accesspoint[/:][a-zA-Z0-9\-]{1,63})[/:]?(?P<key>.*)$r   rg   /rM   r   rV   )recompilematchgroupsplitrP   )rw   Zs3_pathZbucket_format_listZbucket_formatr   Zs3_componentsr   Zs3_keyr!   r!   r"   _find_bucket_key~  s.    
zS3FileSystem._find_bucket_key)returnc                 C   s`   |  |}|d}d|kr&|ddfS | |\}}|d\}}}||| jrV|rV|ndfS dS )a  
        Normalise S3 path string into bucket and key.

        Parameters
        ----------
        path : string
            Input path, like `s3://mybucket/path/to/file`

        Examples
        --------
        >>> split_path("s3://mybucket/path/to/file")
        ['mybucket', 'path/to/file', None]

        >>> split_path("s3://mybucket/path/to/versioned_file?versionId=some_version_id")
        ['mybucket', 'path/to/versioned_file', 'some_version_id']
        r   rV   N?versionId=)_strip_protocollstripr   	partitionrn   )rw   pathr   Zkeypartrg   _rK   r!   r!   r"   
split_path  s    


zS3FileSystem.split_pathc                 C   s:   | j  }d| kr | j|d< d| kr6| j|d< |S )Nconnect_timeoutread_timeout)rp   r   keysr   r   )rw   rp   r!   r!   r"   _prepare_config_kwargs  s    


z#S3FileSystem._prepare_config_kwargsc                    s  | j dk	r|s| j S td | j  t| j| j| j| j	d} fdd|
 D }d  krl| j|d< |  }| jrddlm} d	d
dhfdd|
 D }fdd 
 D  ||d< tf |}| jdkrtjjf | j| _|| j| fD ]&}dD ]}||r d| _ qq q| j}	td|	| j |	| _| jrnt| jfd|i| }
|
 I dH | _ n(| jjdd|i| }
|
 I dH | _ |
| _| jst| | j | j!| j t"| j | _#| j S )zEstablish S3 connection object.
        Returns
        -------
        Session to be closed later with await .close()
        NzSetting up s3fs instance)aws_access_key_idaws_secret_access_keyaws_session_tokenre   c                    s,   i | ]$\}}|d k	r|  |kr||qS r   r   r\   rg   value)ro   r!   r"   r_     s
     z,S3FileSystem.set_session.<locals>.<dictcomp>rs   r   )UNSIGNEDr   r   r   c                    s   i | ]\}}| kr||qS r!   r!   r   	drop_keysr!   r"   r_     s      c                    s   i | ]\}}| kr||qS r!   r!   r   r   r!   r"   r_     s    Zsignature_version)region_namere   Fz/RC: caching enabled? %r (explicit option is %r)configrY   )rY   )$ru   r   r8   ro   r   dictrg   rh   ri   re   itemsr   rs   r   rf   botocorer   r   rv   aiobotocoreZ
AioSessionr1   r   rt   r   Z
get_clientcreate_client
__aenter__r   ra   weakreffinalizeclose_sessionr`   r   r   )rw   refreshr1   Zinit_kwargsrp   r   conf
parametersoptionrt   Z	s3creatorr!   )ro   r   r"   r     s    








   zS3FileSystem.set_sessionc                 C   s   | d k	rz|   rzz"t } | |d d d  W d S  tk
rF   Y nX zt| |jd d d dd W d S  tk
rx   Y nX z|jj	j
j  W n tk
r   Y nX d S )Nr3   )timeout)Z
is_runningr9   Zget_event_loopZcreate_task	__aexit__r}   r   r   Z_clientZ	_endpointZhttp_sessionZ
_connector_closeAttributeError)r`   rY   r!   r!   r"   r     s     zS3FileSystem.close_session  c                    s   | j rddiS | jr(| j| j| jddS | jdks<| jdkrDddiS | jd4 I dH >}|j|dd }|d	 |d
 |d ddW  5 Q I dH R  S Q I dH R X dS )aJ  Get temporary credentials from STS, appropriate for sending across a
        network. Only relevant where the key/secret were explicitly provided.

        Parameters
        ----------
        exp : int
            Time in seconds that credentials are good for

        Returns
        -------
        dict of parameters
        rf   TF)rg   rh   ri   rf   Nsts)ZDurationSecondsZCredentialsZAccessKeyIdZSecretAccessKeyZSessionToken)rf   ri   rg   rh   rv   r   Zget_session_token)rw   expr   credr!   r!   r"   _get_delegated_s3pars2  s"    z"S3FileSystem._get_delegated_s3parsr'   c                 K   s   |dkr| j }|dkr| j}|
dkr.t| j}
|pL| jddpL| jdd}| j }|| | jst|rtt	d|dkr| j
}t| ||||||||||
||	dS )a  Open a file for reading or writing

        Parameters
        ----------
        path: string
            Path of file on S3
        mode: string
            One of 'r', 'w', 'a', 'rb', 'wb', or 'ab'. These have the same meaning
            as they do for the built-in `open` function.
        block_size: int
            Size of data-node blocks if reading
        fill_cache: bool
            If seeking to new a part of the file beyond the current buffer,
            with this True, the buffer will be filled between the sections to
            best support random access. When reading only a few specific chunks
            out of a file, performance may be better if False.
        acl: str
            Canned ACL to set when writing. False sends no parameter and uses the bucket's
            preset default; otherwise it should be a member of the `key_acls` set.
        version_id : str
            Explicit version of the object to open.  This requires that the s3
            filesystem is version aware and bucket versioning is enabled on the
            relevant bucket.
        encoding : str
            The encoding to use if opening the file in text mode. The platform's
            default text encoding is used if not given.
        cache_type : str
            See fsspec's documentation for available cache_type values. Set to "none"
            if no caching is desired. If None, defaults to ``self.default_cache_type``.
        requester_pays : bool (optional)
            If RequesterPays buckets are supported.  If None, defaults to the
            value used when creating the S3FileSystem (which defaults to False.)
        kwargs: dict-like
            Additional parameters used for s3 methods.  Typically used for
            ServerSideEncryption.
        NACLFaclEversion_id cannot be specified if the filesystem is not version aware)

block_sizer   rK   
fill_cacherr   
cache_type
autocommitrx   cache_optionssize)rZ   rl   boolrq   rr   r   r   r   rn   rQ   rm   S3File)rw   r   moder   r   rK   r   r   r   r   rx   r   r1   kwr!   r!   r"   _openU  sD    3



zS3FileSystem._openr   c              
      s   |  |\}}}	|sd}|r.|dd | }|| jksD|sD|rD|rzhtd|  g }
g }| j|||||d2 z.3 d H W }|d dkr|
| qp|| qp6 ||
7 }W n* tk
r } zt|W 5 d }~X Y nX |r|r|s|| j|< |S | j| S )NrV   r   z!Get directory listing page for %s)	max_items	delimiterprefixversionstype	directory)	r   r   dircacher   r8   _iterdirappendr   r   )rw   r   r   r   r   r   r   r   rg   r   dirsfilescrE   r!   r!   r"   _lsdir  s6    	
zS3FileSystem._lsdirc                 C  s:  |r| j std|  I dH  | |I dH }| j r@d}d}nd}d}||}	i }
|dk	rp|
j|d| d |	jf ||||
d	| j}|2 z3 dH W }|d
g D ]4}|d dd dddd}| j	||dd |V  q||g D ]F}| j r|ds|rd|d< |d |d< | j	|||d |V  qq6 dS )zIterate asynchronously over files and directories under `prefix`.

        The contents are yielded in arbitrary order as info dicts.
        zCversions cannot be specified if the filesystem is not version awareNlist_object_versionsVersionslist_objects_v2Contents   )ZMaxItemsZPageSize)r   Prefix	DelimiterZPaginationConfigCommonPrefixesr   r   	DIRECTORYr   )KeySizer-   r   Fr   ZIsLatestfiler   r   r   )
rn   rQ   r   r   get_paginatorr   paginaterq   r   
_fill_info)rw   r   r   r   r   r   rY   r   Zcontents_keypagr   itrD   lr   r!   r!   r"   r     sL    

zS3FileSystem._iterdirc                 C   sb   | d | d< d || d g| d< | d | d< | d}|r^|r^|dkr^| d  d| 7  < d S )	Nr   r   r   r   namerI   nullr   )joinr   )fr   r   rK   r!   r!   r"   r     s    
zS3FileSystem._fill_infoc                    s(   | drtdt j|f|I d H S )N*Cannot traverse all of S3)
startswithrQ   rj   _glob)rw   r   r1   r{   r!   r"   r    s    
zS3FileSystem._globc                    s(  |  |}| |\}}}|s&td|s.|r:|r:td|r`t j|d | |||dI dH S | j|d|dI dH }	|	s|rz| |I dH g}	W n tk
r   g }	Y nX g }
t }i }|	D ]}| 	|d }||kr`|
| d	}t|t|kr"| |d
 d|dddd}|
| g ||< | 	|}||kr`|r`||| kr`|| | ||kr|| | q|
D ],}| 	|d }||kr||| | q||s| D ]2\}}|| jkrt|t|kr|| j|< q|rt|	|
 dd d}	|rdd |	D S dd |	D S )aL  List all files below path.
        Like posix ``find`` command without conditions

        Parameters
        ----------
        path : str
        maxdepth: int or None
            If not None, the maximum number of levels to descend
        withdirs: bool
            Whether to include directory paths in the output. This is True
            when used by glob, but users usually only want files.
        prefix: str
            Only return files that match ``^{path}/{prefix}`` (if there is an
            exact match ``filename == {path}/{prefix}``, it also will be included)
        r  zHCan not specify 'prefix' option alongside 'withdirs'/'maxdepth' options.r   )maxdepthwithdirsdetailNrV   )r   r   r   FrM   r   r   r   )r   r   r   r-   r   r   c                 S   s   | d S )Nr   r!   )xr!   r!   r"   <lambda>d      z$S3FileSystem._find.<locals>.<lambda>)rg   c                 S   s   i | ]}|d  |qS r   r!   r\   or!   r!   r"   r_   f  s      z&S3FileSystem._find.<locals>.<dictcomp>c                 S   s   g | ]}|d  qS r  r!   r  r!   r!   r"   
<listcomp>g  s     z&S3FileSystem._find.<locals>.<listcomp>)r   r   rQ   rj   _findr   _infoFileNotFoundErrorrN   _parentaddrP   r   r   r   sorted)rw   r   r  r  r  r   r   rg   r   r   r   ZsdirsZthisdircacher  pardZpparr]   vr{   r!   r"   r    st    

   






zS3FileSystem._findc              
      s>  |  |d}|st| |\}}}| |I d H rB|s@tn|rL|r*|rb|tkrbtdtzhd|i}|rx||d< |dd p| jdd }	|	rd|	i|d< | j	d|I d H  | 
d	 | 
| W n\ tk
r }
 zt|
W 5 d }
~
X Y n4 tk
r& }
 ztd
||
f W 5 d }
~
X Y nX n| |I d H  d S )Nr   ACL not in %sr   r   r   ZLocationConstraintZCreateBucketConfigurationcreate_bucketrV   zBucket create failed %r: %s)r  )r   rstriprQ   r   _existsFileExistsError	buck_aclsr   ro   r   invalidate_cacher   r   r   _ls)rw   r   r   create_parentsr1   r   rg   r   paramsr   rE   r!   r!   r"   _mkdirk  s<    

  
$zS3FileSystem._mkdirc                    s:   z| j |ddI d H  W n tk
r4   |r.n Y nX d S )NT)r   )r"  r  )rw   r   exist_okr!   r!   r"   	_makedirs  s    zS3FileSystem._makedirsc              
      s   |  |\}}}|r,| |I d H r(ttz| jd|dI d H  W nP tjjk
r } z.dt|krpt||dt|krt	| W 5 d }~X Y nX | 
| | 
d d S )NZdelete_bucketr   ZNoSuchBucketZBucketNotEmptyrV   )r   r  r  r  r   r   
exceptionsr   r<   OSErrorr  )rw   r   r   rg   r   rE   r!   r!   r"   _rmdir  s    

zS3FileSystem._rmdirc                    s   d| j ks|r| jrg S z| dI d H d }W n tk
rH   g  Y S X |D ]B}|d |d< d|d< d|d	< d|d
< d|d< |d |d< |d= qN|| j d< |S | j d S )NrV   Zlist_bucketsZBucketsNamer   r   r   ZBUCKETr-   r   r   r   r   )r   rf   r   r   )rw   r   r   r   r!   r!   r"   
_lsbuckets  s$    

zS3FileSystem._lsbucketsc                    s   |   d  dkr*| |I dH }nd| j ||dI dH }|sd kr| j|  ||dI dH } fdd|D }|st |r|S |r|S tdd |D S )	a  List files in given bucket, or list of buckets.

        Listing is cached unless `refresh=True`.

        Note: only your buckets associated with the login will be listed by
        `ls('')`, not any public buckets (even if already accessed).

        Parameters
        ----------
        path : string/bytes
            location at which to list files
        refresh : bool (=False)
            if False, look in local cache for file details first
        r   rV   r   Nr   )r   r   c                    s.   g | ]&}|d   d kr|d dkr|qS )r   r   r   r   )r  r  r   r!   r"   r    s    z$S3FileSystem._ls.<locals>.<listcomp>c                 S   s   g | ]}|d  qS r  r!   r  r!   r!   r"   r    s     )r   r  r*  r   r  r  r  )rw   r   r  r   r   r   r!   r,  r"   r    s$      
zS3FileSystem._lsc                 C   s   d ||f}z| |}W n tk
r2   Y dS X |d kr@d S | jrN|d krRdS |D ]$}|d |krV|d|krV dS qVd S )Nr   FTr   rI   )r   _ls_from_cacher  rn   r   )rw   r   r   rg   rK   fullpathentriesentryr!   r!   r"   _exists_in_cache  s    zS3FileSystem._exists_in_cachec                    s6  |dkrdS |  |}| |\}}}|r~| ||||}|d k	rF|S z| j||||dI d H  W dS  tk
rz   Y dS X n| j|drdS z| |rW dS W n tk
r   Y nX z$| jd
d|d| j	I d H  W dS  t
k
 r   Y nX z"| jdd	|i| j	I d H  W dS  t
k
r0   Y dS X d S )Nr+  TrJ   Fr   rM   )MaxKeysr   get_bucket_locationr   )r   )r3  )r   r   r1  r  r  r   r   r-  r   rq   r=   )rw   r   r   rg   rK   Zexists_in_cacher!   r!   r"   r    sJ    



  zS3FileSystem._existsc           
   
      s   |  |\}}}|rtd|s8| |I dH r8tdz | jd||d|I dH }W n* tk
r }	 zt|	W 5 d}	~	X Y nX | | | |S )zCreate empty file or truncatez7S3 does not support touching existing versions of filesNz+S3 does not support touching existent files
put_objectr   r   )r4  )r   rQ   r  r   r   r   r  r  )
rw   r   truncatedatar1   r   rg   rK   write_resultexr!   r!   r"   _touch'  s$      zS3FileSystem._touchc                    sh    |\ |d k	s |d k	r:d|||I d H ini  fdd}t|jdI d H S )NRangec                     sT   j d dtpjI d H } z| d  I d H W S | d   X d S )N
get_objectr5  r   )r<  )r   rL   rq   closereadrespr   headrg   rw   versrK   r!   r"   _call_and_read@  s     
z.S3FileSystem._cat_file.<locals>._call_and_readrC   )r   Z_process_limitsrH   rC   )rw   r   rK   startendrD  r!   rA  r"   	_cat_file9  s    zS3FileSystem._cat_file   c           	         s    |\ }t}|tdd k rHjd d|I d H S jd d|I d H  fddttd	tD I d H }d
d t|D }jd d d|idI d H  | d S )Nr#   r   r4  r   r   r   create_multipart_uploadr5  c                    s@   g | ]8\}}j d  |d d ||  dI dH qS )upload_partrM   UploadIdr   
PartNumberrM  r   r   Nr   )r\   rD   offr   	chunksizer7  rg   mpurw   r!   r"   r  ^  s   	z+S3FileSystem._pipe_file.<locals>.<listcomp>r   c                 S   s"   g | ]\}}|d  |d dqS rM   ETagrO  rV  r!   r\   rD   r  r!   r!   r"   r  j  s    complete_multipart_uploadrM  Partsr   r   rM  ZMultipartUpload)r4  )rK  )r   rP   r;   r   	enumerater6   r  )	rw   r   r7  rS  r1   r   r   r   partsr!   rR  r"   
_pipe_fileP  sD         	zS3FileSystem._pipe_filec                    s  |  |\}}}tj|r4|r$d S | |I d H  tj|}	||	 d|krpt|\}
}|
d k	rp|
|d< t	|d}|	t
dd| k r| }| jd|||d|I d H  ||	 n| jd||d|I d H }g }||}|sq0|| jd	|t|d
 |d ||dI d H  |t| qdd t|D }| jd|||d d|idI d H  W 5 Q R X |r| | | |}qnd S )Nr,   r'   r#   r   r4  rJ  rK  r5  rL  rM   rM  rN  c                 S   s"   g | ]\}}|d  |d dqS rU  r!   rX  r!   r!   r"   r    s    z*S3FileSystem._put_file.<locals>.<listcomp>rY  rZ  r[  )r4  )rK  )r   r   r   isdirr"  getsizeset_size	mimetypes
guess_typeopenr;   r>  r   relative_updater   rP   r\  r  r  )rw   lpathrpathcallbackrS  r1   r   rg   r   r   content_typef0chunkrT  r   r]  r!   r!   r"   	_put_filev  sx    
     




zS3FileSystem._put_filec                    sl  t j|rd S |\ td fdd}|ddI d H \}}|| d}d}	zt|d}
z|	dI d H }W n t
k
r   |d7 }|jkr z|  W n tk
r   Y nX ttd| d	 d
I d H  ||	d I d H \}}Y qnY nX |sq4|	t|7 }	|
|}|| qnW 5 Q R X W 5 z|  W n tk
rd   Y nX X d S )N)r6   c                    sZ   j  }| rd|  d|d< jd dtp4j I d H }|d |dd fS )	Nzbytes=-r;  r<  r5  r   r+   )r<  )rq   r   r   rL   r   )r6   r   r@  r   rg   rw   rC  rK   r!   r"   
_open_file  s    
 
z*S3FileSystem._get_file.<locals>._open_filer   r(   i   rM   r2   r3   r4   )r   r   r_  r   intra  r=  r=   rd  r>  r7   rC   r9   r:   r;   rP   writere  )rw   rg  rf  rh  rK   ro  bodycontent_lengthZfailed_reads
bytes_readrj  rk  r   Zsegment_lenr!   rn  r"   	_get_file  s@    



zS3FileSystem._get_filec           	   
      s  |  | \}}}d||f d k	r>| js>tddkrRdddS t||s|  }|d k	r| jrd k	r fdd|D }|r|d S n*fd	d|D }|r|d S dddS |rzp| jd
| jf||dt	| j
I d H }|dd|d |d d||gd|dd|d|ddW S  tk
rX   Y n0 tk
r } zt|ddW 5 d }~X Y nX z| jd| jf||r|dd ndddd| j
I d H }|dddks|dg s|dg rd||gddddW S tW nb tk
rH } zt|ddW 5 d }~X Y n4 tk
rz } ztd |f W 5 d }~X Y nX d S )!Nr   r   )r   rV   r   r   )r   r   r   c                    s*   g | ]"}|d   kr| dkr|qS )r   rI   r   r  )r.  rK   r!   r"   r    s    z&S3FileSystem._info.<locals>.<listcomp>c                    s   g | ]}|d   kr|qS r  r!   r  r,  r!   r"   r    s      head_objectr5  rV  rV   LastModifiedr+   r   r-   ZSTANDARDrI   r,   )rV  rw  r   r   r   r-   rI   r,   F)Z	set_causer   rM   )r   r   r   r2  ZKeyCountr   r   r   )r   r   r   r-   zFailed to list path %r: %s)r   r   r   rn   rQ   rT   r-  r   r1   rL   rq   r   r  r   r   r  r   )	rw   r   r   rg   r   rK   path_version_idr   rE   r!   )r.  r   rK   r"   r    s    



	





zS3FileSystem._infoc                    sP   | j ||dI dH }|d dkr>t|d ddd d	S tt|d	S dS )
a  
        Unique value for current version of file

        If the checksum is the same from one moment to another, the contents
        are guaranteed to be the same. If the checksum changes, the contents
        *might* have changed.

        Parameters
        ----------
        path : string/bytes
            path of file to get checksum for
        refresh : bool (=False)
            if False, look in local cache for file details first

        )r   Nr   r   rV  "rm  r      )r  rp  stripr   r   )rw   r   r   infor!   r!   r"   	_checksumK  s    zS3FileSystem._checksumc                    s  |  |d}d|kr^|| |I d H kr0dS z| |I d H }W dS  tk
r\   Y dS X || jkr| j| D ]}|d |krr dS qrdS | |}|| jkr| j| D ] }|d |kr|d dk  S qdS zt| |I d H W S  tk
r    Y dS X d S )Nr   TFr   r   r   )r   r{  r*  r   r  r   r  r   )rw   r   r   fpparentr   r!   r!   r"   _isdire  s0    


zS3FileSystem._isdirc                    s   | j std| |\}}}i }ddi}g }|d r| jd|f||d| jI d H }||d  ||dd|d	dd
 q.|S )NzLversion specific functionality is disabled for non-version aware filesystemsZIsTruncatedTr   )r   r   r   ZNextVersionIdMarkerrV   ZNextKeyMarker)ZVersionIdMarkerZ	KeyMarker)rn   rQ   r   r   rq   extendr   r   )rw   r   r1   r   rg   r   r   r   r!   r!   r"   _object_version_info  s2    

z!S3FileSystem._object_version_infoc           	         sR   |  |\}}}| jd|f||dt|| jI dH }dd |d  D }|S )zReturn metadata of path.

        Parameters
        ----------
        path : string/bytes
            filename to get metadata for
        refresh : bool (=False)
            (ignored)
        rv  r5  Nc                 S   s   i | ]\}}| d d|qS r   rm  replacer\   r]   r  r!   r!   r"   r_     s     
 z*S3FileSystem._metadata.<locals>.<dictcomp>r.   )r   r   rL   rq   r   )	rw   r   r   r1   r   rg   rK   r5   metar!   r!   r"   	_metadata  s    
zS3FileSystem._metadatac                 C   s<   |  |\}}}| jd||dt|}dd |d D S )zgRetrieve tag key/values for the given path

        Returns
        -------
        {str: str}
        get_object_taggingr5  c                 S   s   i | ]}|d  |d qS r   Valuer!   )r\   r  r!   r!   r"   r_     s      z)S3FileSystem.get_tags.<locals>.<dictcomp>TagSet)r  )r   call_s3rL   )rw   r   r   rg   rK   r5   r!   r!   r"   get_tags  s     zS3FileSystem.get_tagsr  c           
      C   s   |  |\}}}|dkrB| j|d}|| dd | D }n(|dkr^dd | D }ntd| d|i}	| jd|||	d
t| dS )a  Set tags for given existing key

        Tags are a str:str mapping that can be attached to any key, see
        https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/allocation-tag-restrictions.html

        This is similar to, but distinct from, key metadata, which is usually
        set at key creation time.

        Parameters
        ----------
        path: str
            Existing key to attach tags to
        tags: dict str, str
            Tags to apply.
        mode:
            One of 'o' or 'm'
            'o': Will over-write any existing tags.
            'm': Will merge in new tags with existing tags.  Incurs two remote
            calls.
        mr,  c                 S   s   g | ]\}}||d qS r  r!   r  r!   r!   r"   r    s     z)S3FileSystem.put_tags.<locals>.<listcomp>r  c                 S   s   g | ]\}}||d qS r  r!   r  r!   r!   r"   r    s     zMode must be {'o', 'm'}, not %sr  put_object_tagging)r   r   ZTaggingN)r  )r   r  r   r   rQ   r  rL   )
rw   r   tagsr   r   rg   rK   Zexisting_tagsZnew_tagstagr!   r!   r"   put_tags  s$    
 zS3FileSystem.put_tagsc                    s4   | dd}| j|f|I dH }||kr0|| S dS )zGet an attribute from the metadata.

        Examples
        --------
        >>> mys3fs.getxattr('mykey', 'attribute_1')  # doctest: +SKIP
        'value_1'
        r   rm  N)r  r  )rw   r   	attr_namer1   Zxattrr!   r!   r"   	_getxattr  s
    zS3FileSystem._getxattrc           
   	      s   dd |  D }| |\}}}| |I dH }|jf | |pDi }|D ]}|| dkrJ||d qJ||d}	|r~||	d< | jd||	|||ddI dH  || j|< dS )	a  Set metadata.

        Attributes have to be of the form documented in the
        `Metadata Reference`_.

        Parameters
        ----------
        kw_args : key-value pairs like field="value", where the values must be
            strings. Does not alter existing fields, unless
            the field appears here - if the value is None, delete the
            field.
        copy_kwargs : dict, optional
            dictionary of additional params to use for the underlying
            s3.copy_object.

        Examples
        --------
        >>> mys3file.setxattr(attribute_1='value1', attribute_2='value2')  # doctest: +SKIP
        # Example for use with copy_args
        >>> mys3file.setxattr(copy_kwargs={'ContentType': 'application/pdf'},
        ...     attribute_1='value1')  # doctest: +SKIP

        .. _Metadata Reference: http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#object-metadata
        c                 S   s   i | ]\}}| d d|qS r  r  r  r!   r!   r"   r_   #  s     
 z*S3FileSystem._setxattr.<locals>.<dictcomp>Nr5  rI   copy_objectZREPLACE)
CopySourcer   r   r.   ZMetadataDirective)r   r   r  r   rS   r   _metadata_cache)
rw   r   copy_kwargsZkw_argsr   rg   rK   metadataZkw_keysrcr!   r!   r"   	_setxattr	  s*    
zS3FileSystem._setxattrc           	         s    |\}}}|rJj|ddI dH }tj fdd|D  I dH  n<|r tkr`tdtjd|f|| dt|I dH  |s tkrtdtjd	|| d
I dH  dS )a}  Set Access Control on a bucket/key

        See http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl

        Parameters
        ----------
        path : string
            the object to set
        acl : string
            the value of ACL to apply
        recursive : bool
            whether to apply the ACL to all keys below the given path too
        F)r  Nc                    s   g | ]}j | d dqS )F	recursive)_chmodr\   pr   rw   r!   r"   r  S  s     z'S3FileSystem._chmod.<locals>.<listcomp>r  Zput_object_acl)r   r   r   Zput_bucket_acl)r   r   )	r   r  r9   gatherkey_aclsrQ   r   rL   r  )	rw   r   r   r  r1   r   rg   rK   allfilesr!   r  r"   r  A  s.    

zS3FileSystem._chmodr<  c           	         sZ   |  |\}}}|  I dH  | |I dH }|j|tf ||dt|||dI dH S )zGenerate presigned URL to access path by HTTP

        Parameters
        ----------
        path : string
            the key path we are interested in
        expires : int
            the number of seconds this signature will be good for.
        Nr5  )ZClientMethodZParamsZ	ExpiresIn)r   r   r   Zgenerate_presigned_urlr   rL   )	rw   r   expiresZclient_methodr1   r   rg   rK   rY   r!   r!   r"   _urlg  s    
zS3FileSystem._urlc                    s    |\ }|rtdjd dI dH tj fddt|D  I dH }dd t|D }d|i}jd	 d
 |dI dH  | dS )aR  Create single S3 file from list of S3 files

        Uses multi-part, no data is downloaded. The original files are
        not deleted.

        Parameters
        ----------
        path : str
            The final file to produce
        filelist : list of str
            The paths, in order, to assemble into the final file.
        z+Cannot write to an explicit versioned file!rK  r5  Nc                    s0   g | ](\}}j d  d ||d dqS )upload_part_copyrM  rM   )r   r   rM  r  rO  rP  )r\   rD   r   r   rg   r1   rT  rw   r!   r"   r    s   
z'S3FileSystem._merge.<locals>.<listcomp>c                 S   s&   g | ]\}}|d  |d d dqS rM   CopyPartResultrV  rW  r!   rX  r!   r!   r"   r    s   rZ  rY  rM  r[  )r   rQ   r   r9   r  r\  r  )rw   r   filelistr1   rK   r   r]  	part_infor!   r  r"   _merge|  s4       

zS3FileSystem._mergec              
      s   |  |\}}}|  |\}}}	|	r,tdz4||d}
|rD||
d< | jd||||
dI dH  W n^ tk
r } zt|W 5 d}~X Y n6 tk
r } ztd|||f |W 5 d}~X Y nX | | dS )zkCopy file between locations on S3

        Not allowed where the origin is >5GB - use copy_managed
        z Cannot copy to a versioned file!r5  rI   r  )r   r   r  NzCopy failed (%r -> %r): %s)r   rQ   r   r   r   r   r  )rw   path1path2r1   Zbuc1key1Zver1Zbuc2key2Zver2Zcopy_srcrE   r!   r!   r"   _copy_basic  s(    
    &zS3FileSystem._copy_basicc                    s"   |\ } |\}}}	jd||d|I dH }
tj fddtd|d D  I dH }g }d}t|dD ]v\}}|d }|| d }||kr|d }jd	||||
d
 |d||f dI dH }|||d d d ||7 }qzjd|||
d
 d|idI dH  | dS )zzCopy file between locations on S3 as multi-part while preserving
        the etag (using the same part sizes for each partrK  r5  Nc                    s   g | ]}j d  |dqS )rv  )r   r   rO  rP  r\   rD   Zbucket1r  rw   r!   r"   r    s   z5S3FileSystem._copy_etag_preserved.<locals>.<listcomp>rM   r   r+   r  rM  bytes=%i-%ir   r   rO  rM  r  ZCopySourceRanger  rV  rW  rY  rZ  r[  )rK  )r   r   r9   r  r6   r\  r   r  )rw   r  r  r   total_partsr1   Zversion1Zbucket2r  Zversion2rT  Z
part_infosr]  brange_firstrD   r  Z	part_sizebrange_lastpartr!   r  r"   _copy_etag_preserved  sR      

	
z!S3FileSystem._copy_etag_preservedr#   c           	         s   |dk s|dkrt d|\ }jd d|I dH  fddtt||D I dH }d	d t|D }jd
 d d|idI dH  | dS )zCopy file between locations on S3 as multi-part

        block: int
            The size of the pieces, must be larger than 5MB and at most 5GB.
            Smaller blocks mean more calls, only useful for testing.
        rX   r#   z'Copy block size must be 5MB<=block<=5GBrK  r5  Nc                    sB   g | ]:\}\}}j d  |d d d||f dI dH qS )r  rM   rM  r  r  NrP  )r\   rD   r  r  r   rg   rT  r  rw   r!   r"   r    s   


z.S3FileSystem._copy_managed.<locals>.<listcomp>c                 S   s&   g | ]\}}|d  |d d dqS r  r!   rX  r!   r!   r"   r    s   rY  rM  rZ  r[  )rK  )rQ   r   r   r\  r   r  )	rw   r  r  r   blockr1   versionr   r]  r!   r  r"   _copy_managed  s2      
zS3FileSystem._copy_managedc                    s   |  |}| |\}}}| j||||dI dH }|d }	|dddd\}
}
}|r~|r~| j|||	t|dI dH  n@|	tkr| j	||f|I dH  n |rt
| j|||	f|I dH  dS )	a  Copy file between locations on S3.

        preserve_etag: bool
            Whether to preserve etag while copying. If the file is uploaded
            as a single part, then it will be always equalivent to the md5
            hash of the file hence etag will always be preserved. But if the
            file is uploaded in multi parts, then this option will try to
            reproduce the same multipart upload while copying and preserve
            the generated etag.
        rJ   Nr   rV  rV   ry  rm  )r  )r   r   r  r   r{  r   r  rp  MANAGED_COPY_THRESHOLDr  AssertionErrorr  )rw   r  r  Zpreserve_etagr1   r   rg   rC  r|  r   r   Zparts_suffixr!   r!   r"   _cp_file  s     
   zS3FileSystem._cp_filec                    s,   | j d|dI d H }|dg p*|dg S )Nlist_multipart_uploadsr%  r   ZUploadsr   r   rw   r   r   r!   r!   r"   _list_multipart_uploads;  s    z$S3FileSystem._list_multipart_uploadsc                    s4     I dH }tj fdd|D  I dH  dS )z(Remove any partial uploads in the bucketNc                    s&   g | ]}j d  |d |d dqS )abort_multipart_uploadr   rM  r   r   rM  rP  )r\   uploadr   rw   r!   r"   r  E  s   z9S3FileSystem._clear_multipart_uploads.<locals>.<listcomp>)r  r9   r  r  r!   r  r"   _clear_multipart_uploadsA  s    z%S3FileSystem._clear_multipart_uploadsc                    s   |sdS fdd|D }t |dkr.td|  t |dkrJtdfdd	|D d
d}|D ]}| qfjd| |dI dH } fdd	|dg D S )z
        Remove multiple keys with one call

        Parameters
        ----------
        pathlist : list(str)
            The keys to remove, must all be in the same bucket.
            Must have 0 < len <= 1000
        Nc                    s   h | ]}  |d  qS )r   r   r\   r   r   r!   r"   	<setcomp>^  s     z,S3FileSystem._bulk_delete.<locals>.<setcomp>rM   z1Bulk delete files should refer to only one bucket  z1Max number of files to delete in one call is 1000c                    s   g | ]}d   |d iqS )r   rM   r  r  r   r!   r"   r  e  s     z-S3FileSystem._bulk_delete.<locals>.<listcomp>TZObjectsZQuietdelete_objectsr   ZDeletec                    s   g | ]}  d |d  qS )r   r   r!   )r\   r   )r   r!   r"   r  o  s     ZDeleted)rP   rQ   rS   r  r  r   r   )rw   pathlistr1   Zbucketsdelete_keysr   r   r!   r  r"   _bulk_deleteR  s(    
   zS3FileSystem._bulk_deletec              
      sd   |  |\}}}| | z| jd||dI d H  W n* tk
r^ } zt|W 5 d }~X Y nX d S )NZdelete_objectr5  )r   r  r   r   r   )rw   r   r1   r   rg   r   rE   r!   r!   r"   _rm_fileq  s    
zS3FileSystem._rm_filec           
         s   |rBt |trB|\}}}|sB|I d H rB|I d H  j||dI d H }fdd|D  fdd|D }t fddtdt dD dd	d
I d H }	t	j
fdd|D  I d H  fdd|D  t|	g S )Nr  c                    s   g | ]}  |d  r|qS rM   r  r  r   r!   r"   r    s      z$S3FileSystem._rm.<locals>.<listcomp>c                    s   g | ]}  |d  s|qS r  r  r  r   r!   r"   r    s      c                    s"   g | ]}  ||d   qS )r  )r  r  r   rw   r!   r"   r    s   r   r     T)Z
batch_sizeZnofilesc                    s   g | ]}  |qS r!   )r(  )r\   r  r   r!   r"   r    s     c                    s&   g | ]}  |   |fqS r!   )r  r  r  r   r!   r"   r    s   )
isinstancer<   r   _is_bucket_versioned_rm_versioned_bucket_contentsZ_expand_pathr   r6   rP   r9   r  sum)
rw   r   r  r1   r   rg   r   pathsr   r   r!   r  r"   _rmz  s&    
zS3FileSystem._rmc                    s    | j d|dI d H dddkS )NZget_bucket_versioningr%  ZStatusrV   ZEnabledr  r   r!   r!   r"   r    s     z!S3FileSystem._is_bucket_versionedc                    s   |   I dH  | |I dH }|d}|j|d2 zR3 dH W }|dg |dg  }dd |D dd	}|r4| jd
||dI dH  q46 dS )z*Remove a versioned bucket and all contentsNr   r%  r   ZDeleteMarkersc                 S   s   g | ]}|d  |d dqS )r   rI   )r   rI   r!   r  r!   r!   r"   r    s    z>S3FileSystem._rm_versioned_bucket_contents.<locals>.<listcomp>Tr  r  r  )r   r   r   r   r   r   )rw   r   rY   r   plistZobsr  r!   r!   r"   r    s    
z*S3FileSystem._rm_versioned_bucket_contentsc                 C   sN   |d kr| j   n6| |}| j |d  |rJ| j |d  | |}q,d S r   )r   clearr   rS   r  )rw   r   r!   r!   r"   r    s    
zS3FileSystem.invalidate_cachec                   sV   |ddgdd | j D  kr$tdt j|fd|i|2 z3 d H W }|V  q<6 d S )NrV   r  c                 S   s   g | ]}d  |qS )z{}://)rR   r  r!   r!   r"   r    s     z&S3FileSystem._walk.<locals>.<listcomp>zCannot crawl all of S3r  )protocolrQ   rj   _walk)rw   r   r  r1   r   r{   r!   r"   r    s    $zS3FileSystem._walkc                 C   s,   | j |||d}d|krt|d jddS )zBReturn the last modified timestamp of file at `path` as a datetime)r   rK   r   rw  N)tzinfo)r|  IsADirectoryErrorr  )rw   r   rK   r   r|  r!   r!   r"   modified  s    zS3FileSystem.modifiedd   c                 K   s   | j |fd|i|S )Nr  )url)rw   r   Z
expirationr1   r!   r!   r"   sign  s    zS3FileSystem.signc                    s0   | j s
dS t| dd}|dk	r,| I dH  dS )z`Invalidate the region cache (associated with buckets)
        if ``cache_regions`` is turned on.Nr   )rt   r   r  )rw   cacher!   r!   r"   _invalidate_region_cache  s
    z%S3FileSystem._invalidate_region_cachec                    s"   d|ks| drtt| ||S )Nbcompression)r   rQ   S3AsyncStreamedFile)rw   r   r   r1   r!   r!   r"   
open_async  s    zS3FileSystem.open_async)FNNNNTNFNTr[   FNNNNNFFN)N)r   )
r'   NFNNNTNNN)FNr   rV   F)Nr   rV   F)F)NNFrV   )FT)F)F)FFF)TN)NNN)rI  )NNFN)F)F)r  )N)F)r   r<  )r#   )N)F)N)N)NF)r  )r'   )gr   
__module____qualname____doc__Zroot_markerr   rC   r   rZ   r  Z_extra_tokenize_attributesrk   propertyrY   r   r   r   r   r  r   staticmethodr   r   r   r<   r   r   r   r   _connectr~   r   r   Zget_delegated_s3parsr   r   r   r   r  r  findr"  mkdirr$  makedirsr(  rmdirr*  r  r1  r  existsr:  touchrH  r^  r   rl  ru  r  r}  Zchecksumr  r_  r  Zobject_version_infor  r  r  r  r  r  getxattrr  setxattrr  chmodr  r  r  merger  r  r  r  r  r  r  Zclear_multipart_uploadsr  r  r  r  Zis_bucket_versionedr  r  r  r  r  r  Zinvalidate_region_cacher  __classcell__r!   r!   r{   r"   rU      s  S                    <

	
%P

!          
]     
(       
/V
#
	

#&


' 
? 
@
W
"

)
6
$
0.
(
!	




rU   c                       s   e Zd ZdZdZdZdZd" fd
d	Zdd Zdd Z	d#ddZ
dd Zd$ddZdd Zdd Zd%ddZdd Zdd Zd d! Z  ZS )&r   a
  
    Open S3 key as a file. Data is only loaded and cached on demand.

    Parameters
    ----------
    s3 : S3FileSystem
        botocore connection
    path : string
        S3 bucket/key to access
    mode : str
        One of 'rb', 'wb', 'ab'. These have the same meaning
        as they do for the built-in `open` function.
    block_size : int
        read-ahead size for finding delimiters
    fill_cache : bool
        If seeking to new a part of the file beyond the current buffer,
        with this True, the buffer will be filled between the sections to
        best support random access. When reading only a few specific chunks
        out of a file, performance may be better if False.
    acl: str
        Canned ACL to apply
    version_id : str
        Optional version to read the file at.  If not specified this will
        default to the current version of the object.  This is only used for
        reading.
    requester_pays : bool (False)
        If RequesterPays buckets are supported.

    Examples
    --------
    >>> s3 = S3FileSystem()  # doctest: +SKIP
    >>> with s3.open('my-bucket/my-file.txt', mode='rb') as f:  # doctest: +SKIP
    ...     ...  # doctest: +SKIP

    See Also
    --------
    S3FileSystem.open: used to create ``S3File`` objects

    rW   rX   r#   r'   FNTr[   c              
      s  | |\}}}|s td| | _| _t|| _| _ jrX jtkrXtdtd  _d  _	| _
|ppi  _|rddini  _d|kr|dk rtdnX|r|jr| _|j||d _ jd	  _n*|jr|| || _ jd
 _t j|||||	|
||d  j _d _d|kr||r jd jf||dt| j} fdd| D }|d}|dk r  j j  nd _| _! j"| d|kr|d krd jkr jd  jd< d S )Nz%Attempt to open non key-like path: %sr  rb   rc   r$   rX   zBlock size must be >=5MBrJ   r   rI   )r   r   r   r   Fr&   rv  r5  c                    s(   i | ] \}}|t kr| jkr||qS r!   )_PRESERVE_KWARGSrr   r   r   r!   r"   r_   R  s
    
 z#S3File.__init__.<locals>.<dictcomp>r+   TrV  ZIfMatch)#r   rQ   r   rg   rT   rK   r   r  rT  r]  r   rr   rq   rn   r|  detailsr   r  r   rj   rk   fsrY   append_blockr  r   r1   rL   r   rS   rq  catr   locr   )rw   rY   r   r   r   r   rK   r   rr   r   r   rx   r   r   r   rg   rx  rB  r  r{   r   r"   rk     sv    





	


 zS3File.__init__c                 O   s   | j j|| jf||S r   )r  r  rr   )rw   r   Z	kwarglistr1   r!   r!   r"   r   f  s    zS3File._call_s3c              	   C   s   | j r| js|  | jk rd S td|   g | _t| j| j	d}| j
rR| j
|d< | jd|| _| jr| jd| j| j| j	d| jd | jd}| jd|d	 d
 d d S )NzInitiate upload for %sr5  r   rK  r  rM   rM  )r   r   rO  rM  r  r  rV  rW  )rK  )r   r  tell	blocksizer   r8   r]  r   r   rg   r   r   rT  rr   r   r   )rw   r   r   r!   r!   r"   _initiate_uploadi  s,    
	zS3File._initiate_uploadc                 K   s   | j j| j|f|S )zReturn metadata of file.
        See :func:`~s3fs.S3Filesystem.metadata`.

        Metadata is cached unless `refresh=True`.
        )r  r  r   )rw   r   r1   r!   r!   r"   r    s    zS3File.metadatac                 K   s   | j j| j|f|S )zGet an attribute from the metadata.
        See :func:`~s3fs.S3Filesystem.getxattr`.

        Examples
        --------
        >>> mys3file.getxattr('attribute_1')  # doctest: +SKIP
        'value_1'
        )r  r  r   )rw   Z
xattr_namer1   r!   r!   r"   r    s    	zS3File.getxattrc                 K   s*   |   rtd| jj| jfd|i|S )zSet metadata.
        See :func:`~s3fs.S3Filesystem.setxattr`.

        Examples
        --------
        >>> mys3file.setxattr(attribute_1='value1', attribute_2='value2')  # doctest: +SKIP
        z5cannot update metadata while file is open for writingr  )writableNotImplementedErrorr  r  r   )rw   r  r1   r!   r!   r"   r    s
    zS3File.setxattrc                 K   s   | j j| jf|S )z1HTTP URL to read this file (if it already exists))r  r  r   )rw   r1   r!   r!   r"   r    s    z
S3File.urlc              
   C   s   z"t | j| j| j| j||| jdW S  tk
r } zB|jd tj	krpd|jd krpt
| jd | jdd|n W 5 d }~X Y nX d S )N)rq   r   zpre-conditionsrM   r   rV  )filenameZe_tag)_fetch_ranger  r   rg   rK   rq   r'  r0   errnoEINVALr   r  r   )rw   rF  rG  r9  r!   r!   r"   r    s&    
 
zS3File._fetch_rangec                 C   s  | j | j\}}}td| || j| j f  | jrV| j	sV|rV|  | j
k rVd}n | jd d | j| j
 }}|rl|| j| j
 }}t|}d|  k r| j
k  rn nJ|| }| j
| }	|	| jkr|d  }}n"|	d }
|d |
 ||
d   }}t| jd }td| |f  | jd||| jd ||d	}||d
 d}d|kr^|d |d< | j| qv| jr|r|   | S )Nz.Upload for %s, final=%s, loc=%s, buffer loc=%sFr   r   rM   zUpload chunk %s, %srL  rM  rN  rV  rW  ZChecksumSHA256)r  r   r   r   r8   r  bufferr	  r   r  r
  seekr>  rP   part_maxr]  r   rT  r   commit)rw   finalr   rg   r   Zdata1Zdata0Z
data1_size	remainderZremainder_sizer   r  r   Zpart_headerr!   r!   r"   _upload_chunk  sX    

	
zS3File._upload_chunkc                    s  t d|   |  dkrJ| jd k	rt d|   |   | j| j}n| js| jd k	rt d|   | j	d | j
 }tf | j| j|d| j}| jr| j|d< | jd|}qtn6t d|   d	| ji}| jd
| j| j| jd |d}| jjr
|d| _d | _| jd}|d |dd  D ]J | jjkrl fdd| jj D sl| j d   q0d S )Nz	Commit %sr   zEmpty file committed %szOne-shot upload of %s)r   r   r   r   r4  z"Complete multi-part upload for %s rZ  rY  rM  r[  rI   r   rM   c                    s$   g | ]}|d  d   krdqS )r   r   Tr!   )r\   r   r  r   r!   r"   r  	  s     z!S3File.commit.<locals>.<listcomp>)r4  )r   r8   r	  r  
_abort_mpur  r  r   r]  r  r>  r   rg   r   r1   r   r   r}   rT  rn   r   rK   r   r   r  )rw   r8  r7  r   r  r]  r!   r  r"   r    sH    






zS3File.commitc                 C   s   |    d | _d S r   )r  r  r   r!   r!   r"   discard	  s    zS3File.discardc                 C   s,   | j r(| jd| j| j| j d d d | _ d S )Nr  rM  r  )rT  r   r   rg   r   r!   r!   r"   r  "	  s    zS3File._abort_mpu)r'   rX   FNTNTr[   FNN)F)N)F)r   r  r  r  rC   Zpart_minr  rk   r   r  r  r  r  r  r  r  r  r  r  r  r!   r!   r{   r"   r     s6   (           `


5+r   c                   @   s   e Zd Zdd ZdddZdS )r  c                 C   s(   || _ || _|| _d | _d| _d | _d S )Nr   )r  r   r   r$   r  r   )rw   r  r   r   r!   r!   r"   rk   .	  s    zS3AsyncStreamedFile.__init__r   c                    s~   | j d krV| j| j\}}}| jjd||dI d H }t|d d d | _|d | _ | j |I d H }|  jt	|7  _|S )Nr<  r5  ZResponseMetadataZHTTPHeaderszcontent-lengthr   )
r$   r  r   r   r   rp  r   r>  r  rP   )rw   lengthr   rg   genr$   r   r!   r!   r"   r>  6	  s    

zS3AsyncStreamedFile.readN)r   )r   r  r  rk   r>  r!   r!   r!   r"   r  -	  s   r  c              
   C   sV   |d kri }||kr*t d|||| dS t d|||| t| jt| ||||||	S )Nz@skip fetch for negative range - bucket=%s,key=%s,start=%d,end=%dr
  zFetch: %s/%s, %s-%s)r   r8   r   r`   _inner_fetch)r  r   rg   rK   rF  rG  rq   r!   r!   r"   r  A	  s    r  c                    s,    fdd}t |jdI d H S )Nc                     sZ   j d dd f dtI d H } z| d  I d H W S | d   X d S )Nr<  r  rM   )r   r   r;  r   )r<  )r   rL   r=  r>  r?  r   rG  r  rg   rq   rF  rK   r!   r"   rD  R	  s     z$_inner_fetch.<locals>._call_and_readrE  )rH   rC   )r  r   rg   rK   rF  rG  rq   rD  r!   r  r"   r  Q	  s    r  )N)N)N)Er9   r  loggingrb  r   sockettypingr   r   r   r   Zurllib3.exceptionsr   ZfsspecZfsspec.specr   Zfsspec.utilsr   r   r   r   Zfsspec.asynr	   r
   r   r   r   r   Zfsspec.callbacksr   r   r   Zaiobotocore.sessionZaiobotocore.configr   Zbotocore.exceptionsr   r   r   Zbotocore.parsersr   Zs3fs.errorsr   Z
s3fs.utilsr   r   r   r   Zaiohttpr   ImportError	getLoggerr   r    r  r   r7   Z_VALID_FILE_MODESr  r  r  rH   rL   rT   rU   r   r  r  r  r!   r!   r!   r"   <module>   s    




	#              <  V
