U
    er                     @  s0  d dl m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
Z
d dlmZ d dlmZ d dlmZ d dlmZm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 d d	lmZ d d
lmZmZm Z m!Z!m"Z" d dl#m$Z$ ej%dkr
d dl	m&Z& nd dl'm&Z& zd dl(Z(W n e)k
r@   e*dY nX e	j+g e	j,ej-j. f Z/e	j+e e"ge	j0d f Z1e	j+e!ge1f Z2e	j+e!e e"ge	j0d f Z3e	j4e5e	j6e5e	j7e5 f f Z8dddddZ9G dd dZ:G dd de	j;Z<G dd de=Z>G dd dZ?G dd de(j@ZAG dd de(jBZCdS )     )annotationsN)Future)cached_property)GeneratorType)unquoteurljoin)ObjectReceiveStreamObjectSendStream)StapledObjectStream)is_async_callable)ASGIAppMessageReceiveScopeSend)WebSocketDisconnect)   
   )	TypeGuardzThe starlette.testclient module requires the httpx package to be installed.
You can install this with:
    $ pip install httpx
zASGI2App | ASGI3AppzTypeGuard[ASGI3App]appreturnc                 C  s   t | rt| dS t| S )N	__await__)inspectisclasshasattrr   r    r   8/tmp/pip-unpacked-wheel-2mv5qoba/starlette/testclient.py	_is_asgi34   s    

r   c                   @  s4   e Zd ZdZdddddZddd	dd
ddZdS )
_WrapASGI2z7
    Provide an ASGI3 interface onto an ASGI2 app.
    ASGI2AppNoner   c                 C  s
   || _ d S Nr   )selfr   r   r   r   __init__?   s    z_WrapASGI2.__init__r   r   r   )scopereceivesendr   c                   s   |  |}|||I d H  d S r#   r   )r$   r&   r'   r(   instancer   r   r   __call__B   s    
z_WrapASGI2.__call__N)__name__
__module____qualname____doc__r%   r*   r   r   r   r   r    :   s   r    c                   @  s   e Zd ZU ded< ded< dS )_AsyncBackendstrbackenddict[str, typing.Any]backend_optionsN)r+   r,   r-   __annotations__r   r   r   r   r/   G   s   
r/   c                   @  s   e Zd ZdddddZdS )_UpgradeWebSocketTestSessionr"   )sessionr   c                 C  s
   || _ d S r#   )r7   )r$   r7   r   r   r   r%   M   s    z_Upgrade.__init__N)r+   r,   r-   r%   r   r   r   r   r5   L   s   r5   c                   @  s.  e Zd ZdddddddZd dd	d
ZeddddZddddZdddddZddddZ	ddddZ
dddddZdddddZdddddZd dd!d"d#Zd$dd!d%d&Zd<dd(dd)d*d+Zd=d.d/dd0d1d2Zddd3d4Zd dd5d6Zd$dd7d8Zd>d(dd9d:d;Zd-S )?r6   ASGI3Appr   _PortalFactoryTyper"   )r   r&   portal_factoryr   c                 C  s6   || _ || _d | _|| _t | _t | _d | _d S r#   )	r   r&   accepted_subprotocolr:   queueQueue_receive_queue_send_queueextra_headers)r$   r   r&   r:   r   r   r   r%   R   s    

zWebSocketTestSession.__init__r   c                 C  s   t  | _| j|  | _z2| j| j}| ddi | 	 }| 
| W n  tk
rn   | j   Y nX |dd | _|dd | _| S )Ntypezwebsocket.connectsubprotocolheaders)
contextlib	ExitStack
exit_stackenter_contextr:   portalstart_task_soon_runr(   r'   _raise_on_close	Exceptionclosegetr;   r@   )r$   _messager   r   r   	__enter__`   s    

zWebSocketTestSession.__enter__zanyio.Eventc                 C  s   t  S r#   )anyioEventr$   r   r   r   should_closep   s    z!WebSocketTestSession.should_closec                   s   | j   d S r#   )rV   setrU   r   r   r   _notify_closet   s    z"WebSocketTestSession._notify_close
typing.Anyargsr   c              	   G  sR   z| d W 5 | j | j | j  X | j sN| j }t|t	r*|q*d S )N  )
rI   rJ   rX   rG   rN   r?   emptyrO   
isinstanceBaseException)r$   r[   rQ   r   r   r   __exit__w   s    


zWebSocketTestSession.__exit__c              
     s`   ddd fdd}t  4 I dH ,}|||  j I dH  |j  W 5 Q I dH R X dS )zE
        The sub-thread in which the websocket session runs.
        zanyio.abc.TaskGroupr"   )tgr   c              
     s|   zjz  j j jI d H  W nF t k
r8   Y n0 tk
rf } z j	
|  W 5 d }~X Y nX W 5 | j   X d S r#   )cancel_scopecancelr   r&   _asgi_receive
_asgi_sendrS   Zget_cancelled_exc_classr_   r?   put)ra   excrU   r   r   run_app   s    z*WebSocketTestSession._run.<locals>.run_appN)rS   Zcreate_task_groupZ
start_soonrV   waitrb   rc   )r$   rh   ra   r   rU   r   rK      s
    zWebSocketTestSession._runr   c                   s&   | j  rtdI d H  q | j  S )Nr   )r>   r]   rS   sleeprO   rU   r   r   r   rd      s    
z"WebSocketTestSession._asgi_receiverQ   r   c                   s   | j | d S r#   )r?   rf   r$   rQ   r   r   r   re      s    zWebSocketTestSession._asgi_sendc                 C  s*   |d dkr&t |dd|ddd S )NrB   zwebsocket.closecoder\   reason )r   rO   rl   r   r   r   rL      s
    
 
z$WebSocketTestSession._raise_on_closec                 C  s   | j | d S r#   )r>   rf   rl   r   r   r   r(      s    zWebSocketTestSession.sendr0   )datar   c                 C  s   |  d|d d S )Nwebsocket.receiverB   textr(   r$   rp   r   r   r   	send_text   s    zWebSocketTestSession.send_textbytesc                 C  s   |  d|d d S )Nrq   rB   rw   rt   ru   r   r   r   
send_bytes   s    zWebSocketTestSession.send_bytesrs   z"typing.Literal[('text', 'binary')])rp   moder   c                 C  sD   t j|ddd}|dkr*| d|d n| d|dd d S )	N),:F)
separatorsensure_asciirs   rq   rr   utf-8rx   )jsondumpsr(   encode)r$   rp   rz   rs   r   r   r   	send_json   s    zWebSocketTestSession.send_jsonr\   Nintz
str | None)rm   rn   r   c                 C  s   |  d||d d S )Nzwebsocket.disconnect)rB   rm   rn   rt   )r$   rm   rn   r   r   r   rN      s    zWebSocketTestSession.closec                 C  s   | j  }t|tr||S r#   )r?   rO   r^   r_   rl   r   r   r   r'      s    

zWebSocketTestSession.receivec                 C  s"   |   }| | tt|d S )Nrs   )r'   rL   typingcastr0   rl   r   r   r   receive_text   s    
z!WebSocketTestSession.receive_textc                 C  s"   |   }| | tt|d S )Nrw   )r'   rL   r   r   rw   rl   r   r   r   receive_bytes   s    
z"WebSocketTestSession.receive_bytes)rz   r   c                 C  s<   |   }| | |dkr$|d }n|d d}t|S )Nrs   rw   r   )r'   rL   decoder   loads)r$   rz   rQ   rs   r   r   r   receive_json   s    

z!WebSocketTestSession.receive_json)rs   )r\   N)rs   )r+   r,   r-   r%   rR   r   rV   rX   r`   rK   rd   re   rL   r(   rv   ry   r   rN   r'   r   r   r   r   r   r   r   r6   Q   s*    	 r6   c                   @  s6   e Zd Zdddddddd	d
dZdddddZdS )_TestClientTransportTro   r8   r9   boolr0   r2   r"   )r   r:   raise_server_exceptions	root_path	app_stater   c                C  s"   || _ || _|| _|| _|| _d S r#   )r   r   r   r:   r   )r$   r   r:   r   r   r   r   r   r   r%      s
    	z_TestClientTransport.__init__zhttpx.Requesthttpx.Response)requestr   c                   s  j j}j jjdd}j j}j j}j jjdd}ddddd| }d|krl|dd\}}	t|	}
n|}|}
dj	krg }n0|
|krd	|
 fg}nd	| d|
 
 fg}|d
d j	 D 7 }|dkrNj	dd }|d krg }ndd |dD }dt||| j||
 |d ||
g|| j d}t| j|| j}t|ddjt||| j||
 |d ||
gdi i| j d}dddt id d  ddfdd}ddd fdd}z6|  $}|tj|| j||| W 5 Q R X W n0 tk
r> } z| jr.|W 5 d }~X Y nX | jrXsntd nsnd!g t d"td   d< tj!f d#i}d k	r|_" |_#|S )$Nascii)encodingP   i  )httpwshttpswssr|      hosts   hostc                 S  s$   g | ]\}}|   | fqS r   )lowerr   .0keyvaluer   r   r   
<listcomp>   s   z7_TestClientTransport.handle_request.<locals>.<listcomp>>   r   r   sec-websocket-protocolc                 S  s   g | ]}|  qS r   )strip)r   r   r   r   r   r     s     r{   Z	websocket)rB   pathraw_pathr   schemequery_stringrD   clientserversubprotocolsstater   z1.1http.response.debug)rB   http_versionmethodr   r   r   r   r   rD   r   r   
extensionsr   Fstreamr   rA   c                    s   r"  s I d H  ddiS   } t| tr@| d}nn| d krNd}n`t| trz,| d }t|trx|d}d|ddW S  tk
r   dddd Y S X n| }dd|dS )	NrB   zhttp.disconnectr       zhttp.requestT)rB   body	more_body)rB   r   )	is_setri   readr^   r0   r   r   r(   StopIteration)r   Z
body_byteschunk)r   request_completeresponse_completer   r   r'   3  s*    




z4_TestClientTransport.handle_request.<locals>.receiver"   rk   c                   s   | d dkrDrt d| d d< dd | dg D d< d	n| d d
krs\t d rlt d| dd}| dd}jdkrd | |s܈d d   n$| d dkr| d d | d d  d S )NrB   zhttp.response.startz1Received multiple "http.response.start" messages.statusstatus_codec                 S  s    g | ]\}}|  |  fqS r   )r   r   r   r   r   r   W  s   zE_TestClientTransport.handle_request.<locals>.send.<locals>.<listcomp>rD   Tzhttp.response.bodyz<Received "http.response.body" without "http.response.start".z7Received "http.response.body" after response completed.r   r   r   FHEADr   r   r   infotemplatecontext)AssertionErrorrO   r   r   writeseekrW   )rQ   r   r   )r   
raw_kwargsr   r   response_startedr   r   r   r(   O  s:    



z1_TestClientTransport.handle_request.<locals>.sendz(TestClient did not receive any response.i  )r   rD   r   r   )$urlr   netlocr   r   r   querysplitr   rD   r   Zmulti_itemsrO   r   r   r   copyr6   r   r:   r5   r   ioBytesIOcallrS   rT   r_   r   r   httpxZ
ByteStreamr   Responser   r   )r$   r   r   r   r   r   r   default_portr   Zport_stringportrD   rC   r   r&   r7   r'   r(   rI   rg   responser   )r   r   r   r   r   r   r   r   handle_request   s    



 
z#_TestClientTransport.handle_requestN)Tro   )r+   r,   r-   r%   r   r   r   r   r   r      s     r   c                      s  e Zd ZU dZded< dZded< dNddddddddddd
 fddZejddddZ	ddddddZ
dddddddejjddejjdddd d!d"d#d$d%d&dd'ddd(dd)d* fd+d,Zdddejjddejjdd-d d%d&dd'ddd(dd)d.
 fd/d0Zdddejjddejjdd-d d%d&dd'ddd(dd)d.
 fd1d2Zdddejjddejjdd-d d%d&dd'ddd(dd)d.
 fd3d4Zdddddddejjddejjddd d!d"d#d$d%d&dd'ddd(dd)d5 fd6d7Zdddddddejjddejjddd d!d"d#d$d%d&dd'ddd(dd)d5 fd8d9Zdddddddejjddejjddd d!d"d#d$d%d&dd'ddd(dd)d5 fd:d;Zdddejjddejjdd-d d%d&dd'ddd(dd)d.
 fd<d=ZdOdd>d$d?d@ fdAdBZd ddCdDZd$ddEdFdGZdddHdIZdddJdKZdddLdMZ  ZS )P
TestClientFzFuture[None]taskNzanyio.abc.BlockingPortal | NonerI   http://testserverTro   asyncior   r0   r   z#typing.Literal[('asyncio', 'trio')]zdict[str, typing.Any] | Nonezhttpx._types.CookieTypes | Nonezdict[str, str] | Noner"   )
r   base_urlr   r   r1   r3   cookiesrD   follow_redirectsr   c
                   s   t ||p
i d| _t|r |}
ntt|}t|}
|
| _i | _t	| j| j
||| jd}|d krdi }|dd t j| j||||	|d d S )N)r1   r3   )r:   r   r   r   z
user-agentZ
testclient)r   r   rD   	transportr   r   )r/   async_backendr   r   r   r!   r    r   r   r   _portal_factory
setdefaultsuperr%   )r$   r   r   r   r   r1   r3   r   rD   r   Zasgi_appr   	__class__r   r   r%     s8     zTestClient.__init__z6typing.Generator[anyio.abc.BlockingPortal, None, None]rA   c              	   c  s:   | j d k	r| j V  n"tjjf | j}|V  W 5 Q R X d S r#   )rI   rS   from_threadstart_blocking_portalr   )r$   rI   r   r   r   r     s    

zTestClient._portal_factoryzbool | Nonez%bool | httpx._client.UseClientDefault)r   allow_redirectsr   c                 C  sN   t jj}|d k	r$d}t|t |}|d k	r2|}n|d k	rJ|d k	rJtd|S )NzMThe `allow_redirects` argument is deprecated. Use `follow_redirects` instead.z9Cannot use both `allow_redirects` and `follow_redirects`.)r   _clientUSE_CLIENT_DEFAULTwarningswarnDeprecationWarningRuntimeError)r$   r   r   redirectrQ   r   r   r   _choose_redirect_arg  s    zTestClient._choose_redirect_arg)contentrp   filesr   paramsrD   r   authr   r   timeoutr   zhttpx._types.URLTypesz"httpx._types.RequestContent | Nonez_RequestData | Nonez httpx._types.RequestFiles | NonerY   z#httpx._types.QueryParamTypes | Nonezhttpx._types.HeaderTypes | Nonez7httpx._types.AuthTypes | httpx._client.UseClientDefaultz:httpx._types.TimeoutTypes | httpx._client.UseClientDefaultr   )r   r   r   rp   r   r   r   rD   r   r   r   r   r   r   r   c                  s<   |  |}| ||}t j|||||||||	|
|||dS N)r   rp   r   r   r   rD   r   r   r   r   r   )Z
_merge_urlr   r   r   )r$   r   r   r   rp   r   r   r   rD   r   r   r   r   r   r   r   r   r   r   r     s"    
zTestClient.request)r   rD   r   r   r   r   r   r   )
r   r   rD   r   r   r   r   r   r   r   c             
     s(   |  ||}
t j||||||
||	dS N)r   rD   r   r   r   r   r   )r   r   rO   r$   r   r   rD   r   r   r   r   r   r   r   r   r   r   rO     s    zTestClient.getc             
     s(   |  ||}
t j||||||
||	dS r   )r   r   optionsr   r   r   r   r     s    zTestClient.optionsc             
     s(   |  ||}
t j||||||
||	dS r   )r   r   headr   r   r   r   r   1  s    zTestClient.head)r   r   rp   r   r   r   rD   r   r   r   r   r   r   r   c                  s0   |  |
|}t j|||||||||	|||dS r   )r   r   postr$   r   r   rp   r   r   r   rD   r   r   r   r   r   r   r   r   r   r   r   L  s    zTestClient.postc                  s0   |  |
|}t j|||||||||	|||dS r   )r   r   rf   r   r   r   r   rf   o  s    zTestClient.putc                  s0   |  |
|}t j|||||||||	|||dS r   )r   r   patchr   r   r   r   r     s    zTestClient.patchc             
     s(   |  ||}
t j||||||
||	dS r   )r   r   deleter   r   r   r   r     s    zTestClient.deleteztyping.Sequence[str] | Noner6   )r   r   kwargsr   c              
     s   t d|}|di }|dd |dd |dd |d k	rT|d	d
| ||d< zt jd|f| W n( tk
r } z
|j}W 5 d }~X Y n
X td|S )Nzws://testserverrD   
connectionupgradezsec-websocket-keyztestserver==zsec-websocket-versionZ13r   z, GETzExpected WebSocket upgrade)	r   rO   r   joinr   r   r5   r7   r   )r$   r   r   r   rD   rg   r7   r   r   r   websocket_connect  s    
zTestClient.websocket_connectc              	     s   t  }|tjjf j _ |jddfdd}t	t
j\}}t	t
j\}}t||_t||_ j_ j |jdd fdd}| _W 5 Q R X S )Nr"   rA   c                     s
   d  _ d S r#   )rI   r   rU   r   r   reset_portal  s    z*TestClient.__enter__.<locals>.reset_portalc                     s     j d S r#   )r   wait_shutdownr   rI   r$   r   r   r    s    z+TestClient.__enter__.<locals>.wait_shutdown)rE   rF   rH   rS   r   r   r   rI   callbackZcreate_memory_object_streammathinfr
   stream_sendstream_receiverJ   lifespanr   r   wait_startuppop_allrG   )r$   stackr   Zsend1Zreceive1Zsend2Zreceive2r  r   r  r   rR     s     

zTestClient.__enter__rZ   c                 G  s   | j   d S r#   )rG   rN   )r$   r[   r   r   r   r`     s    zTestClient.__exit__c              	     sF   d| j d}z | || jj| jjI d H  W 5 | jd I d H  X d S )Nr  )rB   r   )r   r  r(   r   r  r'   )r$   r&   r   r   r   r    s     zTestClient.lifespanc                   s`    j ddiI d H  dd fdd}| I d H }|d dksDt|d dkr\| I d H  d S )	NrB   zlifespan.startuprY   rA   c                    s&    j  I d H } | d kr" j  | S r#   r  r'   r   resultrQ   rU   r   r   r'     s    
z(TestClient.wait_startup.<locals>.receive)zlifespan.startup.completelifespan.startup.failedr  )r  r(   r   r$   r'   rQ   r   rU   r   r	    s    zTestClient.wait_startupc              
     s   dd fdd} j 4 I d H P  jddiI d H  | I d H }|d dksTt|d dkrl| I d H  W 5 Q I d H R X d S )	NrY   rA   c                    s&    j  I d H } | d kr" j  | S r#   r  r  rU   r   r   r'      s    
z)TestClient.wait_shutdown.<locals>.receiverB   zlifespan.shutdown)zlifespan.shutdown.completelifespan.shutdown.failedr  )r  r  r(   r   r  r   rU   r   r    s    zTestClient.wait_shutdown)r   Tro   r   NNNT)N)r+   r,   r-   Z__test__r4   rI   r%   rE   contextmanagerr   r   r   r   r   r   rO   r   r   r   rf   r   r   r   rR   r`   r  r	  r  __classcell__r   r   r   r   r     s   
        &)	2*(((0'0'0'( r   )D
__future__r   rE   r   r   r   r  r<   sysr   r   concurrent.futuresr   	functoolsr   typesr   urllib.parser   r   rS   Z	anyio.abcZanyio.from_threadr   r	   Zanyio.streams.stapledr
   Zstarlette._utilsr   Zstarlette.typesr   r   r   r   r   Zstarlette.websocketsr   version_infor   Ztyping_extensionsr   ModuleNotFoundErrorr   CallableContextManagerabcZBlockingPortalr9   	AwaitableZASGIInstancer!   r8   Mappingr0   UnionIterableZ_RequestDatar   r    	TypedDictr/   rM   r5   r6   ZBaseTransportr   ZClientr   r   r   r   r   <module>   s\   
  3