o
    ùT·j.s  ã                   @   s  d dl Z d dl mZ d dlZd dlZddlmZmZmZm	Z	 d dl
mZmZ d dlmZ d dlZddlmZmZ ddlmZ dd	lmZ d dlZdd
lmZmZmZ dd„ ZdZdd„ Zdd„ ZG dd„ deƒZ G dd„ de d�Z!dZ"ddddœZ#G dd„ dƒZ$dS )é    N)Ú	lru_cacheé   )ÚrequestsÚnew_sessionÚis_supported_sessionÚ
cookie_jar)ÚurlsplitÚurljoin)ÚBeautifulSoup)ÚutilsÚcache)Ú
frozendict)ÚYfConfig)ÚYFExceptionÚYFDataExceptionÚYFRateLimitErrorc                 C   s0   t | ttjtfƒrdS t| ƒj}h d£}||v S )zDCheck if error is transient (network/timeout) and should be retried.T>   ÚTimeoutÚReadTimeoutÚTimeoutErrorÚConnectTimeoutÚConnectionErrorÚRemoteDisconnectedÚChunkedEncodingError)Ú
isinstancer   ÚsocketÚerrorÚOSErrorÚtypeÚ__name__)Ú	exceptionÚerror_type_nameÚtransient_error_types© r"   úP/home/dinkstrade/pdmp-scanner/venv/lib/python3.10/site-packages/yfinance/data.pyÚ_is_transient_error   s
   
r$   é@   c                 C   s   t | tƒr
| | dœS | S )N)ÚhttpÚhttps)r   Ústr)Úproxyr"   r"   r#   Ú_normalize_proxy!   s   

r*   c                    s*   t  ˆ ¡‡ fdd„ƒ}ˆ j|_ˆ j|_|S )z©
    Decorator transforms mutable dictionary and list arguments into immutable types
    Needed so lru_cache can cache method calls what has dict or list arguments.
    c                     sV   t dd„ | D ƒƒ} dd„ | ¡ D ƒ}t dd„ | D ƒƒ} dd„ | ¡ D ƒ}ˆ | i |¤ŽS )Nc                 S   ó"   g | ]}t |tƒrt|ƒn|‘qS r"   ©r   Údictr   ©Ú.0Úargr"   r"   r#   Ú
<listcomp>/   ó   " z9lru_cache_freezeargs.<locals>.wrapped.<locals>.<listcomp>c                 S   ó(   i | ]\}}|t |tƒrt|ƒn|“qS r"   r,   ©r/   ÚkÚvr"   r"   r#   Ú
<dictcomp>0   ó   ( z9lru_cache_freezeargs.<locals>.wrapped.<locals>.<dictcomp>c                 S   r+   r"   ©r   ÚlistÚtupler.   r"   r"   r#   r1   1   r2   c                 S   r3   r"   r9   r4   r"   r"   r#   r7   2   r8   )r;   Úitems)ÚargsÚkwargs©Úfuncr"   r#   Úwrapped-   s
   z%lru_cache_freezeargs.<locals>.wrapped)Ú	functoolsÚwrapsÚ
cache_infoÚcache_clear)r@   rA   r"   r?   r#   Úlru_cache_freezeargs'   s
   	rF   c                       s,   e Zd ZdZi Ze ¡ Z‡ fdd„Z‡  Z	S )ÚSingletonMetaz6
    Metaclass that creates a Singleton instance.
    c                    sž   | j �B | | jvrtƒ j|i |¤Ž}|| j| < n!d|v s$|r9t|ƒdkr9d|v r-| d¡n|d }| j|   |¡ | j|  W  d   ƒ S 1 sHw   Y  d S )NÚsessionr   )Ú_lockÚ
_instancesÚsuperÚ__call__ÚlenÚgetÚ_set_session)Úclsr=   r>   ÚinstancerH   ©Ú	__class__r"   r#   rL   C   s   
$÷zSingletonMeta.__call__)
r   Ú
__module__Ú__qualname__Ú__doc__rJ   Ú	threadingÚLockrI   rL   Ú__classcell__r"   r"   rR   r#   rG   <   s
    rG   c                   @   s2  e Zd ZdZd2dd„Zdd„ Zdd„ Zd	d
„ Zd3dd„Ze	j
dd„ ƒZe	j
dd„ ƒZe	j
d4dd„ƒZe	j
d4dd„ƒZe	j
dd„ ƒZe	j
dd„ ƒZe	j
d4dd„ƒZe	j
d4dd„ƒZe	j
d5dd „ƒZe	j
d6d!d"„ƒZe	j
d6d#d$„ƒZeeed%�d5d&d'„ƒƒZd5d(d)„Zd*ed+efd,d-„Zd.ejd/e d+ejfd0d1„Z!dS )7ÚYfDataz¬
    Have one place to retrieve data from Yahoo API in order to ease caching and speed up operations.
    Singleton means one session one cookie shared by all threads.
    Nc                 C   sB   d | _ d | _d| _d| _t ¡ | _d| _d | _|  	|pt
ƒ ¡ d S )NFÚbasic)Ú_crumbÚ_cookieÚ
_logged_inÚ_cookie_strategyrW   rX   Ú_cookie_lockÚfundamentals_use_chunkedÚ_sessionrO   r   ©ÚselfrH   r"   r"   r#   Ú__init__V   s   
zYfData.__init__c                 C   sR   | j � | jj ||dœ¡ d| _d| _d | _W d   ƒ d S 1 s"w   Y  d S )N)ÚTÚYT)r`   rb   ÚcookiesÚupdater]   r^   r\   )rd   Úcookie_tÚcookie_yr"   r"   r#   Úset_login_cookieso   s   þ"òzYfData.set_login_cookiesc                 C   s2   | j � || _W d  ƒ dS 1 sw   Y  dS )a!  Thread-safe update of the login flag (also read under this lock in
        _set_cookie_strategy). Auth calls this after verifying the real login
        state, possibly from another thread, so the write must be serialized to
        avoid a stale value clobbering a concurrent fresh login.N)r`   r^   )rd   Úvaluer"   r"   r#   Ú_set_logged_in€   s   "ÿzYfData._set_logged_inc                 C   sž   |d u rd S t |dd ƒd urtdƒ‚t|ƒs tdt|ƒ› d�ƒ‚| j�" || _tjjd ur=t	tjjƒ| j_
W d   ƒ d S W d   ƒ d S 1 sHw   Y  d S )Nr   znCaching sessions (e.g. requests_cache) are not supported. Solution: stop setting session, let yfinance handle.zUnsupported session type z^; expected curl_cffi or requests Session. Solution: stop setting session, let yfinance handle.)Úgetattrr   r   r   r`   rb   r   Únetworkr)   r*   Úproxiesrc   r"   r"   r#   rO   ˆ   s   ý"þzYfData._set_sessionFc                 C   s¸   || j krd S |s| j ¡  z5| j dkr-t ¡  d| j › d�¡ | js)| jj 	¡  d| _ nt ¡  d| j › d�¡ d| _ d | _
d | _W n tyP   | j ¡  ‚ w |sZ| j ¡  d S d S )NÚcsrfztoggling cookie strategy z	 -> basicr[   z -> csrf)r_   r`   Úacquirer   Úget_yf_loggerÚdebugr^   rb   rh   Úclearr]   r\   Ú	ExceptionÚrelease)rd   ÚstrategyÚ	have_lockr"   r"   r#   Ú_set_cookie_strategy™   s*   




þÿzYfData._set_cookie_strategyc                 C   s²   | j d u rdS t| j ƒj}t|ƒdkrdS dd„ | ¡ D ƒ}t|ƒdkr+dd„ |D ƒ}t|ƒdkr=t ¡  d|› �¡ dS t|ƒdkrEdS |d }||| i}t 	¡  
d|¡ d	S )
NFr   c                 S   s   g | ]}d |v r|‘qS )Úyahoor"   ©r/   r5   r"   r"   r#   r1   ¼   ó    z0YfData._save_cookie_curlCffi.<locals>.<listcomp>r   c                 S   s   g | ]}d |vr|‘qS )Úconsentr"   r}   r"   r"   r#   r1   ¿   r~   z1Multiple Yahoo cookies, not sure which to cache: ÚcurlCffiT)rb   r   Ú_cookiesrM   Úkeysr   rt   ru   r   Úget_cookie_cacheÚstore)rd   rh   Ú
yh_domainsÚ	yh_domainÚ	yh_cookier"   r"   r#   Ú_save_cookie_curlCffiµ   s"   
zYfData._save_cookie_curlCffic                 C   sÌ   | j d u rdS t ¡  d¡}|d u st|ƒdkrdS |d }t| ¡ ƒd }|| d d }|j}|dkr9|d }tjj	|tj
jd	�}|tj tj
j¡k }|rXt ¡  d
¡ dS t| j ƒj |¡ || _dS )NFr€   r   Úcookieú/ÚA3g    eÍÝAg     @�@)Útzzcached cookie expiredT)rb   r   rƒ   ÚlookuprM   r:   r‚   ÚexpiresÚdatetimeÚfromtimestampÚtimezoneÚutcÚnowr   rt   ru   r   r�   ri   r]   )rd   Úcookie_dictrh   Údomainr‰   Ú	expiry_tsÚ	expiry_dtÚexpiredr"   r"   r#   Ú_load_cookie_curlCffiÊ   s&   
zYfData._load_cookie_curlCffié   c              
   C   sä   | j d urt ¡  d¡ dS |  ¡ rt ¡  d¡ dS z| jjd|dd� W nE tjj	yF } zt ¡  dt
|ƒ ¡ W Y d }~dS d }~w tyk } zt|ƒrft ¡  dt|ƒj› d	�¡ W Y d }~dS ‚ d }~ww |  ¡  dS )
Núreusing cookieTúreusing persistent cookiezhttps://fc.yahoo.com©ÚurlÚtimeoutÚallow_redirectsz$Handling DNS error on cookie fetch: Fz'Cookie fetch from fc.yahoo.com failed (z), continuing without it)r]   r   rt   ru   r™   rb   rN   r   Ú
exceptionsÚDNSErrorr(   rw   r$   Úwarningr   r   rˆ   )rd   rŸ   Úer"   r"   r#   Ú_get_cookie_basicá   s6   

ý€ÿ€ø	zYfData._get_cookie_basicc                 C   sÄ   | j d urt ¡  d¡ | j S |  ¡ sd S d|ddœ}| jjdi |¤Ž}|j| _ |jdks2d| j v r@t ¡  d| j › �¡ t	ƒ ‚| j d u sJd| j v rSt ¡  d	¡ d S t ¡  d
| j › d�¡ | j S )Núreusing crumbz1https://query1.finance.yahoo.com/v1/test/getcrumbTr�   é­  úToo Many RequestsúDidn't receive crumb ú<html>úDidn't receive crumbú	crumb = 'ú'r"   )
r\   r   rt   ru   r¥   rb   rN   ÚtextÚstatus_coder   )rd   rŸ   Úget_argsÚcrumb_responser"   r"   r#   Ú_get_crumb_basic  s&   
ýzYfData._get_crumb_basicc                 C   s   |   |¡sd S |  |¡S ©N)r¥   r²   )rd   rŸ   r"   r"   r#   Ú_get_cookie_and_crumb_basic  s   

z"YfData._get_cookie_and_crumb_basicc                 C   sÂ  | j d urt ¡  d¡ dS |  ¡ rt ¡  d¡ d| _ dS d|i}i |¥ddi¥}z| jjdi |¤Ž}W n tjj	yH   t ¡  d¡ Y dS w t
|jd	ƒ}|jd
ddid�}|d u ret ¡  d¡ dS |d }t ¡  d|› �¡ |jd
ddid�}|d }	t ¡  d|	› �¡ d}
d}ddgd|	||
|dœ}i |¥d|	› �|dœ¥}i |¥d|	› �|dœ¥}z| jjdi |¤Ž | jjdi |¤Ž W n tjj	y×   t ¡  d¡ Y nw d| _ |  ¡  dS )Nr›   Trœ   rŸ   rž   zhttps://guce.yahoo.com/consentzR_get_cookie_csrf() encountering requests.exceptions.ChunkedEncodingError, abortingFúhtml.parserÚinputÚnameÚ	csrfToken)Úattrsz&Failed to find "csrfToken" in responserm   zcsrfToken = Ú	sessionIdzsessionId='zhttps://finance.yahoo.com/r|   ÚagreeÚdefault)r»   ÚconsentUUIDrº   r¸   ÚoriginalDoneUrlÚ	namespacez6https://consent.yahoo.com/v2/collectConsent?sessionId=)rž   Údataz-https://guce.yahoo.com/copyConsent?sessionId=r"   )r]   r   rt   ru   r™   rb   rN   r   r¡   r   r
   ÚcontentÚfindÚpostrˆ   )rd   rŸ   Ú	base_argsr°   ÚresponseÚsoupÚcsrfTokenInputr¸   ÚsessionIdInputrº   r¾   r¿   rÀ   Ú	post_argsr"   r"   r#   Ú_get_cookie_csrf#  sh   
ÿýúþþþzYfData._get_cookie_csrfc                 C   sÎ   | j d urt ¡  d¡ | j S |  |¡sd S d|dœ}| jjdi |¤Ž}|j| _ |jdks2d| j v r@t ¡  d| j › �¡ t	ƒ ‚| j d u sOd| j v sO| j dkrXt ¡  d	¡ d S t ¡  d
| j › d�¡ | j S )Nr¦   z1https://query2.finance.yahoo.com/v1/test/getcrumb)rž   rŸ   r§   r¨   r©   rª   Ú r«   r¬   r­   r"   )
r\   r   rt   ru   rÊ   rb   rN   r®   r¯   r   )rd   rŸ   r°   Úrr"   r"   r#   Ú_get_crumb_csrf^  s$   

þzYfData._get_crumb_csrfc                 C   s¶   d\}}t  ¡  d| j› d�¡ | j�< | jdkr.|  ¡ }|d u r-| jddd� |  |¡}n|  |¡}|d u rB| jddd� |  ¡ }| j}W d   ƒ ||fS 1 sRw   Y  ||fS )N)NNzcookie_mode = 'r­   rr   r[   T)rz   )r   rt   ru   r_   r`   rÍ   r{   r´   )rd   rŸ   Úcrumbry   r"   r"   r#   Ú_get_cookie_and_crumb{  s$   

€

òñzYfData._get_cookie_and_crumbc                 C   s8   | j || jj||d�}|  |j¡s	 |S |  ||¡}|S )N)Úrequest_methodÚparamsrŸ   )Ú_make_requestrb   rN   Ú_is_this_consent_urlrž   Ú_accept_consent_form©rd   rž   rÑ   rŸ   rÅ   r"   r"   r#   rN   ’  s   þz
YfData.getc                 C   s   | j || jj||||d�S )N)rÐ   ÚbodyrÑ   rŸ   rÀ   )rÒ   rb   rÃ   )rd   rž   rÖ   rÑ   rŸ   rÀ   r"   r"   r#   rÃ      s   zYfData.postc                 C   sì  t |ƒdkrt ¡  d|d d… › d�¡ n
t ¡  d|› �¡ t ¡  d|› �¡ tjjd ur8ttjjƒ| j_	|d u r>i }d|v rFt
dƒ‚z|  ¡ \}}W nA tyd   t ¡  d¡ d | j}}Y n, ty� }	 z t|	ƒr„t ¡  dt|	ƒj› d	�¡ d | j}}n‚ W Y d }	~	nd }	~	ww |d ur™d|i}
ni }
|i |¥|
¥|d
œ}|r«||d< |r·||d< ddi|d< ttjjd ƒD ]1}z
|di |¤Ž}W  n% tyð }	 zt|	ƒrå|tjjk råt d| ¡ n‚ W Y d }	~	q¿d }	~	ww t ¡  d|j› �¡ |jdk�rtz|dk�r|  d¡ n|  d¡ |  |¡\}}W n& t�y'   d }Y n t�yA }	 zt|	ƒ�s5‚ d }W Y d }	~	nd }	~	ww d|d v �rN|d d= |d u�rY||d d< |di |¤Ž}t ¡  d|j› �¡ |jdk�rttƒ ‚|S )NéÈ   zurl=z...zparams=rÎ   z@Don't manually add 'crumb' to params dict, let data.py handle itz=Crumb fetch rate-limited (HTTP 429), continuing without crumbzCookie/crumb fetch failed (z), continuing without crumb)rž   rÑ   rŸ   ÚjsonrÀ   zContent-Typezapplication/jsonÚheadersr   é   zresponse code=i�  r[   rr   rÑ   r§   r"   )rM   r   rt   ru   r   rp   r)   r*   rb   rq   r   rÏ   r   r£   r_   rw   r$   r   r   ÚrangeÚretriesÚ_timeÚsleepr¯   r{   )rd   rž   rÐ   rÖ   rÑ   rŸ   rÀ   rÎ   ry   r¤   ÚcrumbsÚrequest_argsÚattemptrÅ   r"   r"   r#   rÒ   ¤  s”    ÿÿþ€ü

ýþ€þ


€ý

zYfData._make_request)Úmaxsizec                 C   s   |   |||¡S r³   ©rN   )rd   rž   rÑ   rŸ   r"   r"   r#   Ú	cache_getþ  s   zYfData.cache_getc                 C   s4   t  ¡  d|› �¡ | j|||d�}| ¡  | ¡ S )Nzget_raw_json(): )rÑ   rŸ   )r   rt   ru   rN   Úraise_for_statusrØ   rÕ   r"   r"   r#   Úget_raw_json  s   zYfData.get_raw_jsonÚresponse_urlÚreturnc                 C   s2   zt |ƒjot |ƒj d¡W S  ty   Y dS w )zó
        Check if given response_url is consent page

        Args:
            response_url (str) : response.url
    
        Returns:
            True : This is cookie-consent page
            False : This is not cookie-consent page
        zconsent.yahoo.comF)r   ÚhostnameÚendswithrw   )rd   rç   r"   r"   r#   rÓ   	  s   ÿþÿzYfData._is_this_consent_urlÚconsent_resprŸ   c                 C   s  t |jdƒ}| d¡}|s|S | d¡p|j}t|j|ƒ}	 i }| d¡D ]>}| d¡}|s/q%| d¡p5d ¡ }	| d¡p>d	}
|	d
v r_d| ¡ v sTd| ¡ v sT| d¡r^|
d	krZ|
nd||< q%|
||< q%dd„ | 	¡ D ƒ}t
dd„ |D ƒƒszd|d< d|ji}| jj||||dd�}|S )a–  
        Click 'Accept all' to cookie-consent form and return response object.

        Args:
            consent_resp (requests.Response) : Response instance of cookie-consent page
            timeout (int) : Raise TimeoutError if post doesn't respond
    
        Returns:
            response (requests.Response) : Response instance received from the server after accepting cookie-consent post.
        rµ   ÚformÚactionr¶   r·   r   r®   rm   rË   )ÚcheckboxÚradior»   ÚacceptÚcheckedÚ1c                 S   s   h | ]}|  ¡ ’qS r"   )Úlowerr}   r"   r"   r#   Ú	<setcomp>N  s    z.YfData._accept_consent_form.<locals>.<setcomp>c                 s   s    � | ]}d |v pd|v V  qdS )r»   rð   Nr"   r}   r"   r"   r#   Ú	<genexpr>O  s   € z.YfData._accept_consent_form.<locals>.<genexpr>ÚRefererT)rÀ   rÙ   rŸ   r    )r
   r®   rÂ   rN   rž   r	   Úfind_allró   Úhas_attrr‚   Úanyrb   rÃ   )rd   rë   rŸ   rÆ   rì   rí   rÀ   Úinpr·   ÚtypÚvalÚloweredrÙ   rÅ   r"   r"   r#   rÔ     s<   

ÿ€


ÿzYfData._accept_consent_formr³   )F)rš   )Nrš   )NNrš   N)"r   rT   rU   rV   re   rl   rn   rO   r{   r   Úlog_indent_decoratorrˆ   r™   r¥   r²   r´   rÊ   rÍ   rÏ   rN   rÃ   rÒ   rF   r   Úcache_maxsizerä   ræ   r(   ÚboolrÓ   r   ÚResponseÚintrÔ   r"   r"   r"   r#   rZ   P   sR    



 

:Y
ÿÿþrZ   )Ú	metaclasszDhttps://query1.finance.yahoo.com/ws/obi-integration/v1/subscriptionsÚgoldÚsilverÚbronze)é   é   é   c                   @   st   e Zd Zddd„Zdededefdd„ZdedB fd	d
„Zdefdd„Z	dedB fdd„Z
ededB fdd„ƒZdS )ÚAuthNc                 C   s   || _ t|ƒ| _d S r³   )rb   rZ   Ú_datarc   r"   r"   r#   re   d  s   zAuth.__init__rj   rk   rè   c                 C   s,   | j  ||¡ |  ¡ }|st ¡  d¡ |S )aW  
        Set the login cookies and verify they are valid.

        How to Obtain the Cookies:
            1. Open your browser (e.g., Chrome, Firefox).
            2. Log in to Yahoo Finance (https://finance.yahoo.com).
            3. Open the browser's Developer Tools:
               Press `F12` or `Ctrl + Shift + I` (Windows/Linux) or `Cmd + Option + I` (Mac).
            4. Go to the "Application" tab (Chrome) or "Storage" tab (Firefox).
            5. In the "Cookies" section, select `https://finance.yahoo.com`.
            6. Look for the cookies named `T` and `Y`.
            7. Copy the values of these cookies and pass them to this function.

        Args:
            cookie_t (str): The value for the 'T' cookie.
            cookie_y (str): The value for the 'Y' cookie.

        Returns:
            bool: ``True`` if the cookies are valid (the account is logged in),
            ``False`` otherwise (also emitted as a warning). The cookies are
            stored regardless. ``False`` can also mean Yahoo was transiently
            unreachable, so it is not treated as a hard error.
        zTset_login_cookies: the provided cookies are not logged in (or Yahoo is unreachable).)r  rl   Úcheck_loginr   rt   r£   )rd   rj   rk   Ú	logged_inr"   r"   r#   rl   h  s   ÿzAuth.set_login_cookiesc              
   C   s¦   z0| j  t¡}|jdkr(| ¡ pi  d¡}t|tƒr(| d¡r(| j  d¡ |W S | j  d¡ W dS  tyR } zt	j
js=‚ t ¡  d|› �¡ W Y d}~dS d}~ww )aÎ  Fetch the account's subscription entitlement (live, not cached).

        A single lightweight JSON call to the OBI subscriptions endpoint
        determines both login state and subscription tier, avoiding any
        consumer-web-page scraping. The result is intentionally not cached:
        the endpoint is cheap and Yahoo does not rate-limit it at any realistic
        volume, so a fresh call each time keeps the answer from going stale
        (e.g. if the login session expires part-way through a long-running
        process).

        Returns:
            dict | None: The entitlement ``result`` object when logged in, or
            ``None`` when not logged in (anonymous sessions return HTTP 401).
        r×   ÚresultÚguidTFNzError confirming login: )r  rN   Ú_SUBSCRIPTIONS_URLr¯   rØ   r   r-   rn   rw   r   ru   Úhide_exceptionsr   rt   r   )rd   rÅ   r  r¤   r"   r"   r#   Ú_fetch_entitlement‰  s    
€úzAuth._fetch_entitlementc                 C   s   |   ¡ duS )u  Check whether the user is logged in to Yahoo Finance.

        Note: ``False`` during a transient error (e.g. Yahoo briefly
        unreachable) means "could not confirm" rather than "logged out" â€” the
        stored login cookies are kept and remain protected in that case.
        N©r  )rd   r"   r"   r#   r  ¬  s   zAuth.check_loginc                 C   sJ   |   ¡ }|du r
dS dd„ | d¡pg D ƒ}|sdS t |d  d¡d¡S )	aM  Return the Yahoo Finance subscription tier of the logged-in account.

        Read directly from the account's tier id in ``subscriptionView`` (the
        value the account is billed against) rather than inferring it from the
        granted feature set, which Yahoo reshuffles between tiers.

        Returns:
            str | None: ``'gold'``, ``'silver'`` or ``'bronze'`` for a named
            subscription (``'premium'`` for a subscribed tier with no marketed
            name), ``'free'`` when logged in without a subscription, or ``None``
            when not logged in.
        Nc                 S   s   g | ]}|  d ¡dkr|‘qS )rí   ÚACTIVErã   )r/   Úsr"   r"   r#   r1   Å  s    ÿz*Auth.subscription_tier.<locals>.<listcomp>ÚsubscriptionViewÚfreer   ÚtierÚpremium)r  rN   Ú_TIER_NAMES)rd   ÚentitlementÚactiver"   r"   r#   Úsubscription_tierµ  s   zAuth.subscription_tierc                 C   s   |   ¡ }|rd|d iS dS )z’
        Get the logged-in user's details.

        Returns:
            dict | None: ``{'guid': ...}`` if logged in, or ``None`` if not.
        r  Nr  )rd   r  r"   r"   r#   ÚuserË  s   z	Auth.userr³   )r   rT   rU   re   r(   r   rl   r-   r  r  r  Úpropertyr  r"   r"   r"   r#   r
  c  s    
!#	r
  )%rB   r   r   ÚtimerÝ   Ú_httpr   r   r   r   Úurllib.parser   r	   Úbs4r
   r�   rË   r   r   r   Úconfigr   rW   r¡   r   r   r   r$   rÿ   r*   rF   r   rG   rZ   r  r  r
  r"   r"   r"   r#   Ú<module>   s4        