o 3a@s*ddlZddlZddlZddlZddlmZddlmZddlmZddl m Z ddl m Z ddl mZmZmZmZddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZm Z m!Z!ddl"m#Z#ddl$m%Z%m&Z&m'Z'ddl(m)Z)ddl*m+Z+ddl,m-Z-ddl.m/Z/ddl0m1Z1ddl2m3Z3ddl4m5Z5ddl6m7Z7dZ8dZ9de9Z:e7dZ;e7dZGd d!d!Z?d"d#Z@d$d%ZAGd&d'd'eZBGd(d)d)eZCd*d+ZDd,d-ZEd.d/ZFGd0d1d1ZGGd2d3d3eGZHGd4d5d5ZIGd6d7d7eIeGZJGd8d9d9eIeHZKdS):N)copy)partial) HTTPStatus) import_module)BytesIO)unquote_to_bytesurljoinurlparseurlsplit) sync_to_async)settings) ASGIRequest) BaseHandler) WSGIRequest)DjangoJSONEncoder)got_request_exceptionrequest_finishedrequest_started)close_old_connections) HttpRequest QueryDict SimpleCookie)signals) ContextListresolve) force_bytes)SimpleLazyObject) urlencode) is_iterable)_lazy_re_compile) AsyncClientAsyncRequestFactoryClientRedirectCycleErrorRequestFactory encode_fileencode_multipartBoUnDaRyStRiNgz multipart/form-data; boundary=%sz.*; charset=([\w\d-]+);?z^application\/(.+\+)?jsoncs eZdZdZfddZZS)r$z9The test client has been asked to follow a redirect loop.cst|||_|j|_dSN)super__init__ last_responseredirect_chain)selfmessager, __class__4/usr/lib/python3/dist-packages/django/test/client.pyr+0s  zRedirectCycleError.__init__)__name__ __module__ __qualname____doc__r+ __classcell__r2r2r0r3r$.sr$c@s4eZdZdZd ddZddZd ddZd d ZdS) FakePayloada A wrapper around BytesIO that restricts what can be read since data from the network can't be sought and cannot be read outside of its content length. This makes sure that views can't do anything under the test client that wouldn't work in real life. NcCs.t|_d|_d|_|dur||dSdS)NrF)r_FakePayload__content_FakePayload__len read_startedwriter.contentr2r2r3r+=s zFakePayload.__init__cCs|jSr))r;)r.r2r2r3__len__DszFakePayload.__len__cCsZ|js |jdd|_|dur|jpd}|j|ksJd|j|}|j|8_|S)NrTzFCannot read more than the available bytes from the HTTP incoming data.)r<r:seekr;read)r. num_bytesr?r2r2r3rBGs   zFakePayload.readcCs8|jrtdt|}|j||jt|7_dS)Nz.Unable to write a payload after it's been read)r< ValueErrorrr:r=r;lenr>r2r2r3r=Rs  zFakePayload.writer))r4r5r6r7r+r@rBr=r2r2r2r3r96s    r9c csJz|EdHWtt|ttdStt|ttwr))r disconnectrconnect)iterablecloser2r2r3closing_iterator_wrapperZs    rJcCsZd|jkr dksn|jdvr|jrg|_nd|_|jdkr+|jr(g|_|Sd|_|S)z Simulate the behavior of most Web servers by removing the content of responses for HEAD requests, 1xx, 204, and 304 responses. Ensure compliance with RFC 7230, section 3.3.3. d)i0HEAD) status_code streamingstreaming_contentr?method)requestresponser2r2r3conditional_content_removalcs" rVc*eZdZdZdfdd ZddZZS) ClientHandlerz A HTTP Handler that can be used for testing purposes. Use the WSGI interface to compose requests, but return the raw HttpResponse object with the originating WSGIRequest attached to its ``wsgi_request`` attribute. Tc||_tj|i|dSr)enforce_csrf_checksr*r+r.r[argskwargsr0r2r3r+|zClientHandler.__init__cCs|jdur |tttj|j|dttt|}|j |_ | |}t ||||_ |jr>t|j|j|_|Stt|tt|S)N)senderenviron)_middleware_chainload_middlewarerrFrsendr1rGrr[_dont_enforce_csrf_checks get_responserV wsgi_requestrQrJrRrIr)r.rarTrUr2r2r3__call__s&        zClientHandler.__call__Tr4r5r6r7r+rhr8r2r2r0r3rXvsrXcrW)AsyncClientHandlerz"An async version of ClientHandler.TcrYr)rZr\r0r2r3r+r_zAsyncClientHandler.__init__cs|jdur |jddd|vr|d}ntd}ttttjdd|j |dIdHt tt ||}|j |_ ||IdH}t||||_|jrattdd|j|jIdH|_|Sttt|jddIdHt t|S)NT)is_async _body_fileF)thread_sensitive)r`scope)rbrcpopr9rrFrr rdr1rGr r[reget_response_asyncrV asgi_requestrQrJrRrIr)r.rp body_filerTrUr2r2r3rhs0            zAsyncClientHandler.__call__rirjr2r2r0r3rksrkcKs:|dg|d|vrt|d<|dt|dS)z Store templates and contexts that are rendered. The context is copied so that it is an accurate representation at the time of rendering. templatescontextN) setdefaultappendrr)storesignalr`templatervr^r2r2r3store_rendered_templatess r|c sg}dddd}|D]a\}}|durtd|||r*|t|||qt|ts[t|r[|D]$}||rE|t|||q5|fddd |d |d |fDq5q|fd dd |d |d |fDq|d |dgd|S)a+ Encode multipart POST data from a dictionary of form values. The key will be used as the form data name; the value will be transmitted as content. If the value is a file, the contents of the file will be sent as an application/octet-stream; otherwise, str(value) will be sent. cS t|tjSr)rr DEFAULT_CHARSETsr2r2r3to_bytes z"encode_multipart..to_bytescSst|do t|jS)NrB)hasattrcallablerB)thingr2r2r3is_filesz!encode_multipart..is_fileNzeCannot encode None for key '%s' as POST data. Did you mean to pass an empty string or omit the value?c3|]}|VqdSr)r2.0valrr2r3 z#encode_multipart..--%sz)Content-Disposition: form-data; name="%s"rnc3rr)r2rrr2r3r rz--%s--rNs )items TypeErrorextendr& isinstancestrrjoin)boundarydatalinesrkeyvalueitemr2rr3r'sD     r'cCsdd}t|dot|jt}|rtj|jnd}t|dr#|j}n |r-t |d}nd}|dur5d}|p8|}|d||d ||f|d |d || gS) NcSr}r)r~rr2r2r3rrzencode_file..to_bytesnamern content_typerapplication/octet-streamrz8Content-Disposition: form-data; name="%s"; filename="%s"zContent-Type: %srN) rrrrospathbasenamer mimetypes guess_typerB)rrfilerfile_has_string_namefilenamerr2r2r3r&s&    r&c@seZdZdZedddZddZddZd d Zd d Z d dZ d%ddZ de dfddZ d%ddZd&ddZ  d'ddZ  d'ddZ  d'dd Z  d'd!d"Z  d'd#d$ZdS)(r%aV Class that lets you create mock Request objects for use in testing. Usage: rf = RequestFactory() get_request = rf.get('/hello/') post_request = rf.post('/submit/', {'foo': 'bar'}) Once you have a request object you can pass it to any view function, just as if that view had been hooked up using a URLconf. ) json_encodercKs ||_||_t|_t|_dSr))rdefaultsrcookiesrerrors)r.rrr2r2r3r+As zRequestFactory.__init__cKsNdtdd|jDdddddd d d d td |jdddd|j|S)z5 The base environment for a request. z; css |] }d|j|jfVqdS)%s=%sN)r coded_valuermorselr2r2r3rPs  z/RequestFactory._base_environ../ 127.0.0.1GETrn testserver80zHTTP/1.1)rhttprNTF) HTTP_COOKIE PATH_INFO REMOTE_ADDRREQUEST_METHOD SCRIPT_NAME SERVER_NAME SERVER_PORTSERVER_PROTOCOLz wsgi.versionwsgi.url_scheme wsgi.inputz wsgi.errorszwsgi.multiprocesszwsgi.multithreadz wsgi.run_once)rsortedrvaluesr9rrr.rTr2r2r3 _base_environGs, zRequestFactory._base_environcKst|jdi|S)#Construct a generic request object.Nr2)rrrr2r2r3rTfszRequestFactory.requestcCs<|tur tt|St|}|r|d}ntj}t||dS)Nr)encoding)MULTIPART_CONTENTr'BOUNDARYCONTENT_TYPE_REmatchr rr)r.rrrcharsetr2r2r3 _encode_datajs    zRequestFactory._encode_datacCs2t|o t|tttf}|rtj||jdS|S)zu Return encoded JSON if data is a dict, list, or tuple and content_type is application/json. )cls) JSON_CONTENT_TYPE_RErrdictlisttuplejsondumpsr)r.rr should_encoder2r2r3 _encode_jsonvszRequestFactory._encode_jsoncCs,|j}|jr |d|j7}t|}|dS)N; iso-8859-1)rparamsrdecode)r.parsedrr2r2r3 _get_path~s  zRequestFactory._get_pathNFcK8|durin|}|jd|fd|idt|ddi|S)zConstruct a GET request.Nrsecure QUERY_STRINGTdoseqgenericrr.rrrextrar2r2r3get  zRequestFactory.getcKs@||durin||}|||}|jd|||fd|i|S)zConstruct a POST request.NPOSTr)rrr)r.rrrrr post_datar2r2r3posts zRequestFactory.postcKr)zConstruct a HEAD request.NrOrrTrrrr2r2r3headrzRequestFactory.headcKs|jd|fd|i|S)zConstruct a TRACE request.TRACErr)r.rrrr2r2r3traceszRequestFactory.tracernrcKs|jd|||fd|i|S)zConstruct an OPTIONS request.OPTIONSrrr.rrrrrr2r2r3optionss zRequestFactory.optionscK(|||}|jd|||fd|i|S)zConstruct a PUT request.PUTrrrrr2r2r3put zRequestFactory.putcKr)zConstruct a PATCH request.PATCHrrrr2r2r3patchrzRequestFactory.patchcKr)zConstruct a DELETE request.DELETErrrr2r2r3deleterzRequestFactory.deletec Kstt|}t|tj}||||rdnd|rdndd}|r/|tt||t|d||| dsF|d d } | |d<|j d i|S) $Construct an arbitrary HTTP request.443rhttpsr)rrrr)CONTENT_LENGTH CONTENT_TYPErrrNr2) r rrr rrupdaterEr9rencoderrT) r.rSrrrrrrr query_stringr2r2r3rs$       zRequestFactory.generic)NF)FrnrF)r4r5r6r7rr+rrTrrrrrrrrrrrrrr2r2r2r3r%4s:        r%c@s.eZdZdZddZddZ  d d d Zd S) r"a Class that lets you create mock ASGI-like Request objects for use in testing. Usage: rf = AsyncRequestFactory() get_request = await rf.get('/hello/') post_request = await rf.post('/submit/', {'foo': 'bar'}) Once you have a request object you can pass it to any view function, including synchronous ones. The reason we have a separate class here is: a) this makes ASGIRequest subclasses, and b) AsyncTestClient can subclass it. c KsXddiddddgdddgd |j|}|d d d td d|jDf|S)zThe base scope for a request.versionz3.0rz1.1rr)rrr)asgitype http_versionclientserverschemerSheadersr scookies; css&|]}d|j|jfdVqdS)rasciiN)rrrrr2r2r3rs  z2AsyncRequestFactory._base_scope..)rrxrrrr)r.rTrpr2r2r3 _base_scopes(    zAsyncRequestFactory._base_scopecKs2d|vr |d}ntd}t|jdi||S)rrmrnNr2)rqr9r r )r.rTrtr2r2r3rTs zAsyncRequestFactory.requestrnrFc Kstt|}t|tj}|||d|rdndf|rdnddgd}|rA|dd tt|d fd |d fgt ||d <| d d} | durO| |d <|ddd| D7<| dsi|d|d<|j di|S)rrrrrr)shosts testserver)rSrr r r r scontent-lengthr s content-typermfollowNcSs(g|]\}}|d|dfqS)r latin1)lowerr)rrrr2r2r3 &sz/AsyncRequestFactory.generic..rrr2)r rrr rrrrErr9rqrrrT) r.rSrrrrrrrrr2r2r3rs.        zAsyncRequestFactory.genericNr)r4r5r6r7r rTrr2r2r2r3r"s  r"c@sXeZdZdZddZddZeddZdd Zdd d Z dd dZ ddZ ddZ d S) ClientMixinzC Mixin with common methods between Client and AsyncClient. cKst|_dS)z3Store exceptions when they are generated by a view.N)sysexc_info)r.r^r2r2r3store_exc_info5szClientMixin.store_exc_infocCs2|j|_|jr|j\}}}d|_|jr|dSdS)z Look for a signaled exception, clear the current context exception data, re-raise the signaled exception, and clear the signaled exception from the local cache. N)rraise_request_exception)r.rU_ exc_valuer2r2r3check_exception9s zClientMixin.check_exceptioncCsJttj}|jtj}|r||jS|}||j |jtj<|S)z%Return the current session variables.) rr SESSION_ENGINErrSESSION_COOKIE_NAME SessionStorersave session_key)r.enginecookiesessionr2r2r3r!Fs  zClientMixin.sessioncKs0ddlm}|di|}|r||dSdS)z Set the Factory to appear as if it has successfully logged into a site. Return True if login is possible or False if the provided credentials are incorrect. r) authenticateTFNr2)django.contrib.authr"_login)r. credentialsr"userr2r2r3loginRs  zClientMixin.loginNcCs,dd}|dur |}||_|||dS)NcSs6ddlm}tjD]}||}t|dr|Sq dS)Nr) load_backendget_user)r#r(r AUTHENTICATION_BACKENDSr)r( backend_pathbackendr2r2r3 get_backendas   z,ClientMixin.force_login..get_backend)r,r$)r.r&r,r-r2r2r3 force_login`s zClientMixin.force_logincCsddlm}t}|jr|j|_n ttj}||_|||||jtj }|jj |j |<ddtj tj p8ddd}|j ||dS)Nr)r'r)zmax-agerdomainrexpires)r#r'rr!rr rrrrrrSESSION_COOKIE_DOMAINSESSION_COOKIE_SECUREr)r.r&r,r'rTrsession_cookie cookie_datar2r2r3r$ms"      zClientMixin._logincCsXddlm}m}t}|jr|j|_|||_n ttj}| |_||t |_ dS)z z Client.request..rrNr2)rrr|idrtemplate_renderedrGrrr<rFrrrTrrurvr8rrresolver_matchrErr)r.rTraron_template_render signal_uid exception_uidrUr2rDr3rTs2       zClient.requestNc >||_tj|f||d|}|r|j|fd|i|}|S)z-Request a response from the server using GET.rrr)rr*r_handle_redirectsr.rrrrrrUr0r2r3r z Client.getc B||_tj|f|||d|}|r|j|f||d|}|S)z.Request a response from the server using POST.rrrrr)rr*rrOr.rrrrrrrUr0r2r3r z Client.postc rM)z.Request a response from the server using HEAD.rNr)rr*rrOrPr0r2r3rrQz Client.headrnrc rR)z1Request a response from the server using OPTIONS.rSrT)rr*rrOrUr0r2r3rrVzClient.optionsc rR)z(Send a resource to the server using PUT.rSrT)rr*rrOrUr0r2r3rrVz Client.putc rR)z*Send a resource to the server using PATCH.rSrT)rr*rrOrUr0r2r3rrVz Client.patchc rR)z$Send a DELETE request to the server.rSrT)rr*rrOrUr0r2r3rrVz Client.deletec rM)z#Send a TRACE request to the server.rNr)rr*rrOrPr0r2r3r rQz Client.tracec KsVg|_tjtjtjtjtjf}|j|vr|j}|j}| ||jft |}|j r.|j |d<|j r6|j |d<|j r@t|j |d<|j} | dsPt|jd| } |jtjtjfvro|jd} | dvri|j|d<t|| } n |j} t|j}d }| | f||d d |}||_|d |d d vrtd |dt|dkrtd|d|j|vs|S)zY Follow any redirects by requesting responses from the server using GET. rrrrrr)rrrNF)rrrzRedirect loop detected.)r,zToo many redirects.)r-rMOVED_PERMANENTLYFOUND SEE_OTHERTEMPORARY_REDIRECTPERMANENT_REDIRECTrPurlrxr r hostnameportrr startswithrrTrquerygetattrrrr$rE) r.rUrrrredirect_status_codes response_urlr-r^rrequest_methodr2r2r3rO(sJ           +zClient._handle_redirectsFT)NFF)rnrFF)rnFF)rnrn)r4r5r6r7r+rTrrrrrrrrrrOr8r2r2r0r3r#s.,     r#cs*eZdZdZdfdd ZddZZS) r!z An async version of Client that creates ASGIRequests and calls through an async request path. Does not currently support "follow" on its methods. FTc r:r;)r*r+rkr<rrrr=r0r2r3r+ir>zAsyncClient.__init__c s<dvr td|jd i}i}tt|}dt}tjj||ddt}tj|j |dz| |IdH}Wtjj |dtj |dntjj |dtj |dw| |||_ |_|dg|_|d|_t|j||_tfd d |_|jrt|jd kr|jd |_|jr|j|j|S)a The master request method. Compose the scope dictionary and pass to the handler, return the result of the handler. Assume defaults for the query environment, which can be overridden using the arguments to the request. rz?AsyncClient request methods do not accept the follow parameter.r?r@rBNrurvcrC)Nrrr2rDr2r3rErFz%AsyncClient.request..rrr2)NotImplementedErrorr rr|rGrrHrGrrr<rFrrrTrrurvr8rrrIrErr)r.rTrprrJrKrLrUr2rDr3rTps<      zAsyncClient.requestrg)r4r5r6r7r+rTr8r2r2r0r3r!bsr!)Lrrrrr functoolsrrr importlibrior urllib.parserrr r asgiref.syncr django.confr django.core.handlers.asgir django.core.handlers.baserdjango.core.handlers.wsgirdjango.core.serializers.jsonrdjango.core.signalsrrr django.dbr django.httprrr django.testrdjango.test.utilsr django.urlsrdjango.utils.encodingrdjango.utils.functionalrdjango.utils.httprdjango.utils.itercompatrdjango.utils.regex_helperr __all__rrrr Exceptionr$r9rJrVrXrkr|r'r&r%r"rr#r!r2r2r2r3s`                    $ 0. 6)UmE