o
    oĎiC                     @   s  d dl Z d dlZd dlmZmZ d dlmZmZmZm	Z	m
Z
mZmZ ddlmZmZ ddlmZ ddlmZ ddlmZ d	d
lmZ z d dlmZ d dlmZmZ d dlmZ d dlm Z  d dl!Z"W n e#yp   ded _$Y nw edG dd deZ%e%j&e%_dS )    N)PathPurePosixPath)AnyCallableDictIterableOptionalTupleUnion   )Clientregister_client_class)implementation_registry)FileCacheMode)CloudPathException   )S3Path)Session)TransferConfig
S3Transfer)Config)ClientErrorFs3c                       s  e Zd ZdZdddddddddddejdfdee dee dee dee ded	 d
ee ded dee	ee
f  dee	eejf  dee ded dee dee f fddZdedeeef fddZdede	eejf defddZdedee fddZdedefdd Zdefd!d"Zd6dedeeeef  fd#d$Zd7d&ed'ed(edefd)d*Zd7ded+eddfd,d-Zde	eejf dedefd.d/Zdedefd0d1Zd8ded3e defd4d5Z!  Z"S )9S3ClientzClient class for AWS S3 which handles authentication with AWS for [`S3Path`](../s3path/)
    instances. See documentation for the [`__init__` method][cloudpathlib.s3.s3client.S3Client.__init__]
    for detailed authentication options.NFaws_access_key_idaws_secret_access_keyaws_session_tokenno_sign_requestbotocore_sessionzbotocore.session.Sessionprofile_nameboto3_sessionr   file_cache_modelocal_cache_direndpoint_urlboto3_transfer_configr   content_type_method
extra_argsc                    s  |
pt d}
|dur| _n
t|||||d _|r: jjd|
ttjjdd _	 jj
d|
ttjjdd _
n jjd|
d _	 jj
d|
d _
| _|du rUi }| _dd	 | D  _d
d	 | D  _ fdd	dD  _|
 _t j|	||d dS )a   Class constructor. Sets up a boto3 [`Session`](
        https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html).
        Directly supports the same authentication interface, as well as the same environment
        variables supported by boto3. See [boto3 Session documentation](
        https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html).

        If no authentication arguments or environment variables are provided, then the client will
        be instantiated as anonymous, which will only have access to public buckets.

        Args:
            aws_access_key_id (Optional[str]): AWS access key ID.
            aws_secret_access_key (Optional[str]): AWS secret access key.
            aws_session_token (Optional[str]): Session key for your AWS account. This is only
                needed when you are using temporarycredentials.
            no_sign_request (Optional[bool]): If `True`, credentials are not looked for and we use unsigned
                requests to fetch resources. This will only allow access to public resources. This is equivalent
                to `--no-sign-request` in the [AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/).
            botocore_session (Optional[botocore.session.Session]): An already instantiated botocore
                Session.
            profile_name (Optional[str]): Profile name of a profile in a shared credentials file.
            boto3_session (Optional[Session]): An already instantiated boto3 Session.
            file_cache_mode (Optional[Union[str, FileCacheMode]]): How often to clear the file cache; see
                [the caching docs](https://cloudpathlib.drivendata.org/stable/caching/) for more information
                about the options in cloudpathlib.eums.FileCacheMode.
            local_cache_dir (Optional[Union[str, os.PathLike]]): Path to directory to use as cache
                for downloaded files. If None, will use a temporary directory. Default can be set with
                the `CLOUDPATHLIB_LOCAL_CACHE_DIR` environment variable.
            endpoint_url (Optional[str]): S3 server endpoint URL to use for the constructed boto3 S3 resource and client.
                Parameterize it to access a customly deployed S3-compatible object store such as MinIO, Ceph or any other.
            boto3_transfer_config (Optional[dict]): Instantiated TransferConfig for managing
                [s3 transfers](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/customizations/s3.html#boto3.s3.transfer.TransferConfig)
            content_type_method (Optional[Callable]): Function to call to guess media type (mimetype) when
                writing a file to the cloud. Defaults to `mimetypes.guess_type`. Must return a tuple (content type, content encoding).
            extra_args (Optional[dict]): A dictionary of extra args passed to download, upload, and list functions as relevant. You
                can include any keys supported by upload or download, and we will pass on only the relevant args. To see the extra
                args that are supported look at the upload and download lists in the
                [boto3 docs](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/customizations/s3.html#boto3.s3.transfer.S3Transfer).
        AWS_ENDPOINT_URLN)r   r   r   r   r   r   signature_versionr#   config)r#   c                 S       i | ]\}}|t jv r||qS  )r   ALLOWED_DOWNLOAD_ARGS.0kvr-   r-   T/home/jeff/fluffinator/venv/lib/python3.10/site-packages/cloudpathlib/s3/s3client.py
<dictcomp>s       z%S3Client.__init__.<locals>.<dictcomp>c                 S   r,   r-   )r   ALLOWED_UPLOAD_ARGSr/   r-   r-   r3   r4   v   r5   c                    "   i | ]}| j v r| j | qS r-   _extra_argsr0   r1   selfr-   r3   r4   |   s
    

)RequestPayerExpectedBucketOwner)r"   r%   r!   )osgetenvsessr   resourcer   botocoresessionUNSIGNEDr   clientr$   r9   itemsboto3_dl_extra_argsboto3_ul_extra_argsboto3_list_extra_args_endpoint_urlsuper__init__)r<   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   	__class__r;   r3   rM      sT   6


zS3Client.__init__
cloud_pathreturnc                 C   sH   | j |j|jjdi | j}|d |d |d |dd |d dS )NLastModifiedContentLengthETagContentTypeMetadata)last_modifiedsizeetagcontent_typeextrar-   )r   ObjectSummarybucketkeygetrH   )r<   rP   datar-   r-   r3   _get_metadata   s   
zS3Client._get_metadata
local_pathc                 C   s6   t |}| j|j|j}|jt|| j| jd |S )Nr   	ExtraArgs)	r   r   Objectr]   r^   download_filestrr$   rH   )r<   rP   rb   objr-   r-   r3   _download_file   s   zS3Client._download_filec                 C   s   |j sdS | |S )Ndir)r^   _s3_file_query)r<   rP   r-   r-   r3   _is_file_or_dir   s   
zS3Client._is_file_or_dirc                    sZ   |j s& fdddD }z jjdd|ji| W dS  ty%   Y dS w  |d uS )Nc                    r7   r-   r8   r:   r;   r-   r3   r4      s    z$S3Client._exists.<locals>.<dictcomp>)r>   BucketTFr-   )r^   rF   head_bucketr]   r   rk   )r<   rP   r[   r-   r;   r3   _exists   s   
zS3Client._existsc              	   C   s   z| j jd	|j|jdd| j W dS  t| j jjfyG   |jdd }t	dd | j
|jjjd	d|i| jdD d Y S w )
zFBoto3 query used for quick checks of existence and if path is file/dir/rm   Keyfilec                 s   s    | ]}d V  qdS )rj   Nr-   )r0   rh   r-   r-   r3   	<genexpr>   s
    
z*S3Client._s3_file_query.<locals>.<genexpr>Prefixr   Nr-   )rF   head_objectr]   r^   rstriprH   r   
exceptions	NoSuchKeynextr   rm   objectsfilterrJ   limit)r<   rP   r^   r-   r-   r3   rk      s0   
zS3Client._s3_file_queryc              
   #   s
    j s |r
td fddj dg D E d H  d S  j}|r.|ds.|d7 }t }jd}|j	d j ||rAdnddj
D ]}|d	g D ]$}|d
d}||vru j  j  d| dfV  || qQ|dg D ]}	|	dt|d  }
t|
jD ]+}|t|d }||vrt|dkr j  j  d| dfV  || q|	dd}||v rq||	ddr|	ddkr j  j  d| dfV  || q| j  j  d|	d dfV  q|qId S )NztCannot recursively list all buckets and contents; you can get all the buckets then recursively list each separately.c                 3   s,    | ]}  j |d   dfV  qdS )NameTN)	CloudPathcloud_prefix)r0   brP   r<   r-   r3   rt      s
    
z%S3Client._list_dir.<locals>.<genexpr>Bucketsrp   list_objects_v2 )rm   ru   	DelimiterCommonPrefixesru   TContentsrr   .Sizer   Fr-   )r]   NotImplementedErrorrF   list_bucketsr_   r^   endswithsetget_paginatorpaginaterJ   rw   r   r   addlenr   parentsrg   )r<   rP   	recursiveprefixyielded_dirs	paginatorresultresult_prefix	canonical
result_keyo_relative_pathparentparent_canonicalr-   r   r3   	_list_dir   sz   



zS3Client._list_dirTsrcdst
remove_srcc                 C   s   ||kr(| j |j|j}|jd|j|jd| |di dd| j |S | j |j|j}|j|j|jd| j	| j
d |rG| | |S )Nrq   r[   REPLACE)
CopySourcerV   MetadataDirective)rd   r   r-   )r   re   r]   r^   	copy_fromra   r_   rI   copyrH   r$   _remove)r<   r   r   r   otargetr-   r-   r3   
_move_file"  s&   
zS3Client._move_file
missing_okc                 C   s   | j |d}|dkr0| j|j|jjdi | j}|dddvr.td| d| d S |dkrt| j	|j}|j}|rI|
d	sI|d	7 }|jjdd
|i| jjdi | j}|d dddvrrtd| d| d S |s~td| dd S )N)rP   rs   ResponseMetadataHTTPStatusCode)      zDelete operation failed for z with response: rj   rp   ru   r   z(Cannot delete file that does not exist: z# (consider passing missing_ok=True)r-   )rl   r   re   r]   r^   deleterJ   r_   r   rm   r   r{   r|   FileNotFoundError)r<   rP   r   file_or_dirrespr]   r   r-   r-   r3   r   9  s8   
zS3Client._removec                 C   sr   | j |j|j}| j }| jd ur,| t|\}}|d ur$||d< |d ur,||d< |jt|| j	|d |S )NrU   ContentEncodingrc   )
r   re   r]   r^   rI   r   r%   rg   upload_filer$   )r<   rb   rP   rh   r&   rZ   content_encodingr-   r-   r3   _upload_fileZ  s   

zS3Client._upload_filec                 C   s>   t tjd}| jjd| j|d}|jd|j|jddd}|S )zApparently the best way to get the public URL is to generate a presigned URL
        with the unsigned config set. This creates a temporary unsigned client to generate
        the correct URL
        See: https://stackoverflow.com/a/48197877
        r(   r   r*   
get_objectrq   r   Params	ExpiresIn)	r   rC   rE   rA   rF   rK   generate_presigned_urlr]   r^   )r<   rP   unsigned_configunsigned_clienturlr-   r-   r3   _get_public_urli  s   zS3Client._get_public_url  expire_secondsc                 C   s    | j jd|j|jd|d}|S )Nr   rq   r   )rF   r   r]   r^   )r<   rP   r   r   r-   r-   r3   _generate_presigned_urlz  s   z S3Client._generate_presigned_url)F)T)r   )#__name__
__module____qualname____doc__	mimetypes
guess_typer   rg   boolr
   r   r?   PathLiker   dictrM   r   r   r   ra   r   ri   rl   ro   rk   r   r	   r   r   r   r   r   intr   __classcell__r-   r-   rN   r3   r      sj    	
m 	 O ! r   )'r   r?   pathlibr   r   typingr   r   r   r   r   r	   r
   rF   r   r   	cloudpathr   enumsr   rx   r   s3pathr   boto3.sessionr   boto3.s3.transferr   r   botocore.configr   botocore.exceptionsr   botocore.sessionrC   ModuleNotFoundErrordependencies_loadedr   r   r-   r-   r-   r3   <module>   s.    $  n