U
    Zf݁                     @   s  d ddgZ dZ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Zddl	Z	ddl
m
Z
mZ ddlmZm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mZmZm Z  ddl!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+ dZ,dZ-dZ.dZ/dZ0dZ1dZ2dZ3dZ4G dd de5Z6G dd de5Z7d$ddZ8G dd de5Z9G d d  d e9eZ:G d!d de9eZ;G d"d# d#e<Z=dS )%DropboxDropboxTeamcreate_sessionz12.0.2    N)datetime	timedelta)AuthError_validatorRateLimitError_validator)files)PathRootPathRoot_validatorPathRootError_validator)DropboxBase)DropboxTeamBase)ApiError	AuthErrorBadInputError	HttpErrorPathRootErrorInternalServerErrorRateLimitError)API_HOSTAPI_CONTENT_HOSTAPI_NOTIFICATION_HOSTHOST_APIHOST_CONTENTHOST_NOTIFYpinned_sessionDEFAULT_TIMEOUT)stone_serializerszDropbox-API-Path-Rooti  i,  zDropbox-API-Select-AdminzDropbox-API-Select-UseruserZteamZappZnoauthc                   @   s   e Zd ZdZdddZdS )RouteResultz+The successful result of a call to a route.Nc                 C   sR   t |tjstdt| |dk	rBt |tjjsBtdt| || _|| _	dS )a3  
        :param str obj_result: The result of a route not including the binary
            payload portion, if one exists. Must be serialized JSON.
        :param requests.models.Response http_resp: A raw HTTP response. It will
            be used to stream the binary-body payload of the response.
        z#obj_result: expected string, got %rNz4http_resp: expected requests.models.Response, got %r)

isinstancesixstring_typesAssertionErrortyperequestsmodelsResponse
obj_result	http_resp)selfr)   r*    r,   :/tmp/pip-unpacked-wheel-qnjxxdf1/dropbox/dropbox_client.py__init__G   s    
zRouteResult.__init__)N__name__
__module____qualname____doc__r.   r,   r,   r,   r-   r    D   s   r    c                   @   s   e Zd ZdZdd ZdS )RouteErrorResultz&The error result of a call to a route.c                 C   s   || _ || _dS )a  
        :param str request_id: A request_id can be shared with Dropbox Support
            to pinpoint the exact request that returns an error.
        :param str obj_result: The result of a route not including the binary
            payload portion, if one exists.
        N)
request_idr)   )r+   r5   r)   r,   r,   r-   r.   Z   s    zRouteErrorResult.__init__Nr/   r,   r,   r,   r-   r4   W   s   r4      c                 C   s   t | |d}|r||_|S )ae  
    Creates a session object that can be used by multiple :class:`Dropbox` and
    :class:`DropboxTeam` instances. This lets you share a connection pool
    amongst them, as well as proxy parameters.

    :param int max_connections: Maximum connection pool size.
    :param dict proxies: See the `requests module
            <http://docs.python-requests.org/en/latest/user/advanced/#proxies>`_
            for more details.
    :rtype: :class:`requests.sessions.Session`. `See the requests module
        <http://docs.python-requests.org/en/latest/user/advanced/#session-objects>`_
        for more details.
    )pool_maxsizeca_certs)r   proxies)Zmax_connectionsr9   r8   sessionr,   r,   r-   r   d   s    c                   @   s   e Zd ZdZdZdZdZdZddddddeddddddfdd	Z	d'd
dZ
d(ddZdd ZedfddZd)ddZd*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d%d& ZdS )-_DropboxTransportzd
    Responsible for implementing the wire protocol for making requests to the
    Dropbox API.
    2downloaduploadrpcN   c                 C   s.  |s|s|
r|st d|dk	r8t|ts8t d||rH|
sHt d|dk	rnt|dksft|tsnt d|| _|| _|	| _|
| _	|| _
|| _|| _|| _|rt|tjjst d||| _nt|d| _|| _d	t }|r|| _d
||| _nd| _|| _td| _tttttti| _ || _!dS )a  
        :param str oauth2_access_token: OAuth2 access token for making client
            requests.
        :param int max_retries_on_error: On 5xx errors, the number of times to
            retry.
        :param Optional[int] max_retries_on_rate_limit: On 429 errors, the
            number of times to retry. If `None`, always retries.
        :param str user_agent: The user agent to use when making requests. This
            helps us identify requests coming from your application. We
            recommend you use the format "AppName/Version". If set, we append
            "/OfficialDropboxPythonSDKv2/__version__" to the user_agent,
        :param session: If not provided, a new session (connection pool) is
            created. To share a session across multiple clients, use
            :func:`create_session`.
        :type session: :class:`requests.sessions.Session`
        :param dict headers: Additional headers to add to requests.
        :param Optional[float] timeout: Maximum duration in seconds that
            client will wait for any single packet from the
            server. After the timeout the client will give up on
            connection. If `None`, client will wait forever. Defaults
            to 100 seconds.
        :param str oauth2_refresh_token: OAuth2 refresh token for refreshing access token
        :param datetime oauth2_access_token_expiration: Expiration for oauth2_access_token
        :param str app_key: application key of requesting application; used for token refresh
        :param str app_secret: application secret of requesting application; used for token refresh
            Not required if PKCE was used to authorize the token
        :param list scope: list of scopes to request on refresh.  If left blank,
            refresh will request all available scopes for application
        :param str ca_certs: a path to a file of concatenated CA certificates in PEM format.
            Has the same meaning as when using :func:`ssl.wrap_socket`.
        zBOAuth2 access token or refresh token or app key/secret must be setNzExpected dict, got {}z%app_key is required to refresh tokensr   Scope list must be of type listz*Expected requests.sessions.Session, got {})r8   zOfficialDropboxPythonSDKv2/z{}/{}dropbox)"BadInputExceptionr!   dictformatlenlist_oauth2_access_token_oauth2_refresh_token_oauth2_access_token_expiration_app_key_app_secret_scope_max_retries_on_error_max_retries_on_rate_limitr&   sessionsSession_sessionr   _headers__version___raw_user_agent_user_agentlogging	getLogger_loggerr   r   r   r   r   r   	_host_map_timeout)r+   oauth2_access_tokenmax_retries_on_errormax_retries_on_rate_limit
user_agentr:   headerstimeoutoauth2_refresh_tokenoauth2_access_token_expirationapp_key
app_secretscoper8   Zbase_user_agentr,   r,   r-   r.      sP    .  z_DropboxTransport.__init__c                 C   sh   |  |p| j|p| j|p| j|p$| j|p,| j|p4| j|p<| j|pD| j|	pL| j	|
pT| j
|p\| j|pd| jS )a  
        Creates a new copy of the Dropbox client with the same defaults unless modified by
        arguments to clone()

        See constructor for original parameter descriptions.

        :return: New instance of Dropbox client
        :rtype: Dropbox
        )	__class__rH   rN   rO   rV   rR   rS   r[   rI   rJ   rK   rL   rM   )r+   r\   r]   r^   r_   r:   r`   ra   rb   rc   rd   re   rf   r,   r,   r-   clone   s    z_DropboxTransport.clonec              	   C   sV  |    |jd pd}|jd }|d |j }|jdkrH|d|j7 }|jd pTd}	t|j|}
|d	kr|tj	kr|j
d
 }| j|||	|
|||d}t|j}t|tr|j}|}nPt|tr|j}|d }|d}|o|d}|o|d}ntdt| tj||dd}t|tr8t|j|||n|	| jkrN||jfS |S d	S )a  
        Makes a request to the Dropbox API and in the process validates that
        the route argument and result are the expected data types. The
        request_arg is converted to JSON based on the arg_data_type. Likewise,
        the response is deserialized from JSON and converted to an object based
        on the {result,error}_data_type.

        :param host: The Dropbox API host to connect to.
        :param route: The route to make the request to.
        :type route: :class:`stone.backends.python_rsrc.stone_base.Route`
        :param request_arg: Argument for the route that conforms to the
            validator specified by route.arg_type.
        :param request_binary: String or file pointer representing the binary
            payload. Use None if there is no binary payload.
        :param Optional[float] timeout: Maximum duration in seconds
            that client will wait for any single packet from the
            server. After the timeout the client will give up on
            connection. If `None`, will use default timeout set on
            Dropbox object.  Defaults to `None`.
        :return: The route's result.
        hostapiauth/   z_v{}styler?   NZ   ra   erroruser_messagetextlocalez7Expected RouteResult or RouteErrorResult, but res is %sF)strict)check_and_refresh_access_tokenattrsnameversionrE   r   json_encodeZarg_typer	   Zlist_folder_longpollra   request_json_string_with_retryjsonloadsr)   r!   r    Zresult_typer4   Z
error_typegetr$   r%   json_compat_obj_decoder   r5   _ROUTE_STYLE_DOWNLOADr*   )r+   Zroute	namespacerequest_argrequest_binaryra   ri   	auth_type
route_nameroute_styleserialized_argresZdecoded_obj_resultZreturned_data_typeobjrr   Zuser_message_textZuser_message_localedeserialized_resultr,   r,   r-   request  sb    

	



  
z_DropboxTransport.requestc                 C   sX   | j o
| j}| j o0| j p0t ttd | jk}| j }|sB|rT|rT| j| j	d dS )zi
        Checks if access token needs to be refreshed and refreshes if possible
        :return:
        seconds)rf   N)
rI   rK   rJ   r   utcnowr   TOKEN_EXPIRATION_BUFFERrH   refresh_access_tokenrM   )r+   Zcan_refreshZneeds_refreshZneeds_tokenr,   r,   r-   rv   h  s    z0_DropboxTransport.check_and_refresh_access_tokenc                 C   s   |dk	r&t |dkst|ts&td| jr2| jsB| jd dS | jd d	|}d| j| jd}| j
rx| j
|d	< |rd
|}||d< t}| jr| j}| jj|||d}| | | }|d | _t tt|d d | _dS )z
        Refreshes an access token via refresh token if available

        :param host: host to hit token endpoint with
        :param scope: list of permission scopes for access token
        :return:
        Nr   rA   zPUnable to refresh access token without                 refresh token and app keyzRefreshing access token.zhttps://{}/oauth2/tokenrefresh_token)Z
grant_typer   Z	client_idZclient_secret rf   )datara   Zaccess_tokenZ
expires_inr   )rF   r!   rG   rC   rI   rK   rY   warninginforE   rL   joinr   r[   rR   postraise_dropbox_error_for_respr|   rH   r   r   r   intrJ   )r+   ri   rf   urlbodyra   r   Ztoken_contentr,   r,   r-   r   v  s4    




z&_DropboxTransport.refresh_access_tokenc              	   C   sT   t |}| j|||||||d}	t |	j}
t|	trL|	jdk	rL|
|	jfS |
S dS )a  
        Makes a request to the Dropbox API, taking a JSON-serializable Python
        object as an argument, and returning one as a response.

        :param host: The Dropbox API host to connect to.
        :param route_name: The name of the route to invoke.
        :param route_style: The style of the route.
        :param str request_arg: A JSON-serializable Python object representing
            the argument for the route.
        :param auth_type str
        :param Optional[bytes] request_binary: Bytes representing the binary
            payload. Use None if there is no binary payload.
        :param Optional[float] timeout: Maximum duration in seconds
            that client will wait for any single packet from the
            server. After the timeout the client will give up on
            connection. If `None`, will use default timeout set on
            Dropbox object.  Defaults to `None`.
        :return: The route's result as a JSON-serializable Python object.
        rp   N)r|   dumpsr{   r}   r)   r!   r    r*   )r+   ri   r   r   r   r   r   ra   r   r   r   r,   r,   r-   request_json_object  s    
	
z%_DropboxTransport.request_json_objectc              
   C   sl  d}d}	d}
| j d| z| j|||||||dW S  tk
r } z<|jr||j r||
r^ q~| j d|j |   d}
n W 5 d}~X Y q tk
r } zF|d7 }|| j	krd	| t

  }| j d
|j| t| n W 5 d}~X Y q tk
rd } zV|	d7 }	| jdks"| j|	krR|jdk	r4|jnd}| j d| t| n W 5 d}~X Y qX qdS )z
        See :meth:`request_json_object` for description of parameters.

        :param request_json_arg: A string representing the serialized JSON
            argument to the route.
        r   FzRequest to %srp   z:ExpiredCredentials status_code=%s: Refreshing and RetryingTNrm      z2HttpError status_code=%s: Retrying in %.1f secondsg      @z$Ratelimit: Retrying in %.1f seconds.)rY   r   request_json_stringr   rq   Zis_expired_access_tokenstatus_coder   r   rN   randomtimesleepr   rO   backoff)r+   ri   r   r   request_json_argr   r   ra   attemptZrate_limit_errorsZhas_refresheder   r,   r,   r-   r{     s^    
  z0_DropboxTransport.request_json_string_with_retryc                 C   s^  || j krtd| t|tjtdfs:tdt| | j | }| ||}	d| ji}
|	dd
d}t|ks|t|kr| jrd| j |
d	< | jr|
| j nt|kr| jdks| jdkrtd
td| j| jd}d|d|
d	< | jr*|
| j n|tkrntd|d}d}|| jkrLd|
d< |}nH|| jkrf||
d< d}n.|| jkrd|
d< ||
d< |}ntd| |dkr| j}| jj|	|
|||d}|  | |j!"d}|j#dkr|j$d}t%||S || jkr
|j!d }n2|j!"ddks0t&d|j!"d |j$d}|| jkrRt'||S t'|S dS )zc
        See :meth:`request_json_string_with_retry` for description of
        parameters.
        zUnknown value for host: %rNz.expected request_binary as binary type, got %sz
User-Agentr    ,z	Bearer %sAuthorizationzAClient id and client secret are required for routes with app authz{}:{}zutf-8zBasic {}zUnhandled auth type: {}Fapplication/jsonzContent-TypezDropbox-API-ArgTzapplication/octet-streamzUnknown operation style: %r)r`   r   streamra   x-dropbox-request-idi  i  i  zdropbox-api-resultcontent-type4Expected content-type to be application/json, got %r)(rZ   
ValueErrorr!   r"   binary_typer%   	TypeError_get_route_urlrV   replacesplit	USER_AUTH	TEAM_AUTHrH   rS   updateAPP_AUTHrK   rL   rC   base64	b64encoderE   encodedecodeNO_AUTH_ROUTE_STYLE_RPCr   _ROUTE_STYLE_UPLOADr[   rR   r   r   r`   r~   r   contentr4   r$   r    )r+   ri   	func_namer   r   r   r   ra   Zfq_hostnamer   r`   Z
auth_typesauth_headerr   r   rr5   Zraw_respr,   r,   r-   r     s    









z%_DropboxTransport.request_json_stringc                 C   s  |j d}|jdkr*t||j|jn|jdkrzD| d dkrj|j d}ttd}t	||nt
||jW n  tk
r   t
||jY nX n&|jdkr|j dd	kstd
|j d tt| d }t	||n|jtkrtt| d }t||n|jdkrd}|j dd	krVtt| d }|j}n$|j d}|dk	rvt|}nd}t|||n<|jdkrdS d|j  krdksn t||j|jdS )zpChecks for errors from a res and handles appropiately.

        :param res: Response of an api request.
        r   i  i  rq   Zinvalid_grantZinvalid_access_tokeni  r   r   r   i  Nzretry-afterr      i+  )r`   r~   r   r   rs   r|   r   r   r   r   r   r   r$   HTTP_STATUS_INVALID_PATH_ROOTr   r   r   retry_afterr   r   r   )r+   r   r5   errr   Zretry_after_strr,   r,   r-   r   e  sb    

 

 
 
 


z._DropboxTransport.raise_dropbox_error_for_respc                 C   s   dj |tj|dS )zReturns the URL of the route.

        :param str hostname: Hostname to make the request to.
        :param str route_name: Name of the route.
        :rtype: str
        z)https://{hostname}/{version}/{route_name})hostnamery   r   )rE   r   _API_VERSION)r+   r   r   r,   r,   r-   r     s
    z _DropboxTransport._get_route_url   c              
   C   sJ   t |d6}t|  ||D ]}|| q"W 5 Q R X W 5 Q R X dS )a  
        Saves the body of an HTTP response to a file.

        :param str download_path: Local path to save data to.
        :param http_resp: The HTTP response whose body will be saved.
        :type http_resp: :class:`requests.models.Response`
        :rtype: None
        wbN)open
contextlibclosingiter_contentwrite)r+   download_pathr*   	chunksizefcr,   r,   r-   _save_body_to_file  s    	z$_DropboxTransport._save_body_to_filec                 C   sB   t |tstd| jr"| j ni }tt||t< | j	|dS )a  
        Creates a clone of the Dropbox instance with the Dropbox-API-Path-Root header
        as the appropriate serialized instance of PathRoot.

        For more information, see
        https://www.dropbox.com/developers/reference/namespace-guide#pathrootmodes

        :param PathRoot path_root: instance of PathRoot to serialize into the headers field
        :return: A :class: `Dropbox`
        :rtype: Dropbox
        z)path_root must be an instance of PathRoot)r`   )
r!   r
   r   rS   copyr   rz   r   PATH_ROOT_HEADERrh   )r+   Z	path_rootnew_headersr,   r,   r-   with_path_root  s    
z _DropboxTransport.with_path_rootc                 C   s   | j   dS )zV
        Cleans up all resources like the request session/network connection.
        N)rR   closer+   r,   r,   r-   r     s    z_DropboxTransport.closec                 C   s   | S Nr,   r   r,   r,   r-   	__enter__  s    z_DropboxTransport.__enter__c                 G   s   |    d S r   )r   )r+   argsr,   r,   r-   __exit__  s    z_DropboxTransport.__exit__)NNNNNNNNNNNN)N)N)N)N)r   )r0   r1   r2   r3   r   r   r   r   r   r.   rh   r   rv   r   r   r   r{   r   r   r   r   r   r   r   r   r,   r,   r,   r-   r;   x   sb   
a            
, 
T. 
2 
E 
_1
r;   c                   @   s   e Zd ZdZdS )r   z
    Use this class to make requests to the Dropbox API using a user's access
    token. Methods of this class are meant to act on the corresponding user's
    Dropbox.
    Nr0   r1   r2   r3   r,   r,   r,   r-   r     s   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	r   z
    Use this class to make requests to the Dropbox API using a team's access
    token. Methods of this class are meant to act on the team, but there is
    also an :meth:`as_user` method for assuming a team member's identity.
    c                 C   s   |  t|S )a  
        Allows a team credential to assume the identity of an administrator on the team
        and perform operations on any team-owned content.

        :param str team_member_id: team member id of administrator to perform actions with
        :return: A :class:`Dropbox` object that can be used to query on behalf
            of this admin of the team.
        :rtype: Dropbox
        )&_get_dropbox_client_with_select_headerSELECT_ADMIN_HEADERr+   team_member_idr,   r,   r-   as_admin  s    
zDropboxTeam.as_adminc                 C   s   |  t|S )aK  
        Allows a team credential to assume the identity of a member of the
        team.

        :param str team_member_id: team member id of team member to perform actions with
        :return: A :class:`Dropbox` object that can be used to query on behalf
            of this member of the team.
        :rtype: Dropbox
        )r   SELECT_USER_HEADERr   r,   r,   r-   as_user  s    
zDropboxTeam.as_userc                 C   sR   | j r| j  ni }|||< t| j| j| j| j| j| j| j	| j
|| j| j| jdS )ap  
        Get Dropbox client with modified headers

        :param str select_header_name: Header name used to select users
        :param str team_member_id: team member id of team member to perform actions with
        :return: A :class:`Dropbox` object that can be used to query on behalf
            of a member or admin of the team
        :rtype: Dropbox
        )r\   rb   rc   r]   r^   ra   r_   r:   r`   rd   re   rf   )rS   r   r   rH   rI   rJ   rN   rO   r[   rU   rR   rK   rL   rM   )r+   Zselect_header_namer   r   r,   r,   r-   r     s     z2DropboxTeam._get_dropbox_client_with_select_headerN)r0   r1   r2   r3   r   r   r   r,   r,   r,   r-   r     s   c                   @   s   e Zd ZdZdS )rC   z
    Thrown if incorrect types/values are used

    This should only ever be thrown during testing, app should have validation of input prior to
    reaching this point
    Nr   r,   r,   r,   r-   rC     s   rC   )r6   NN)>__all__rT   r   r   r|   rW   r   r   r&   r"   r   r   Zdropbox.authr   r   rB   r	   Zdropbox.commonr
   r   r   Zdropbox.baser   Zdropbox.base_teamr   Zdropbox.exceptionsr   r   r   r   r   r   r   Zdropbox.sessionr   r   r   r   r   r   r   r   Zstone.backends.python_rsrcr   r   r   r   r   r   r   r   r   r   objectr    r4   r   r;   r   r   	ExceptionrC   r,   r,   r,   r-   <module>   sR   $	(

    a<