B
    `r                 @   s@  d Z 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	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlZddgZG dd deZ G dd dej!Z"G dd dej#Z$G dd de%Z&dS )zF
Routines for testing WSGI applications.

Most interesting is TestApp
    )unicode_literalsN)	b64encode)StringIO)BytesIO)string_types)binary_type)	text_type)http_cookiejar)urlparse)to_bytes)escape_cookie_value)TestResponse)forms)lint)utilsTestAppTestRequestc               @   s   e Zd Zdd ZdS )AppErrorc          	   G   s   t |tr|d}d}x|D ]~}t |tjr\|j}t |tr|jrR||j}qt|}n6t |try|d}W n tk
r   t|}Y nX ||f7 }qW || }t	
| | d S )Nutf8 )
isinstancer   decodewebobResponsebodycharsetreprUnicodeDecodeError	Exception__init__)selfmessageargsZstr_argsargr   r   r   S/home/kop/projects/devel/pgwui/test_venv/lib/python3.7/site-packages/webtest/app.pyr   ,   s$    





zAppError.__init__N)__name__
__module____qualname__r   r   r   r   r$   r   *   s   r   c               @   s    e Zd ZdZdd Zdd ZdS )CookiePolicyzOA subclass of DefaultCookiePolicy to allow cookie set for
    Domain=localhost.c             C   s   |j dkrdS tj| ||S )Nz
.localhostT)domainr	   DefaultCookiePolicyreturn_ok_domain)r    cookierequestr   r   r$   r+   F   s    
zCookiePolicy.return_ok_domainc             C   s   |j dkrdS tj| ||S )Nz
.localhostT)r)   r	   r*   set_ok_domain)r    r,   r-   r   r   r$   r.   L   s    
zCookiePolicy.set_ok_domainN)r%   r&   r'   __doc__r+   r.   r   r   r   r$   r(   B   s   r(   c               @   s   e Zd ZdZeZdS )r   zA subclass of webob.RequestN)r%   r&   r'   r/   r   ResponseClassr   r   r   r$   r   S   s   c               @   s6  e Zd ZdZeZd:ddZdd Zdd	 Ze	eeZ
e	d
d Zdd Zdd Zdd Zd;ddZd<ddZd=ddZd>ddZd?ddZd@ddZdAd d!Zed"Zed#Zed$Zed%Zd&d' ZdBd(d)ZdCd*d+Zd,d- Zd.d/ Z dDd0d1Z!d2d3 Z"ej#ddddddfd4d5Z$d6d7 Z%e&d8d9 Z'dS )Er   aX  
    Wraps a WSGI application in a more convenient interface for
    testing. It uses extended version of :class:`webob.BaseRequest`
    and :class:`webob.Response`.

    :param app:
        May be an WSGI application or Paste Deploy app,
        like ``'config:filename.ini#test'``.

        .. versionadded:: 2.0

        It can also be an actual full URL to an http server and webtest
        will proxy requests with `WSGIProxy2
        <https://pypi.org/project/WSGIProxy2/>`_.
    :type app:
        WSGI application
    :param extra_environ:
        A dictionary of values that should go
        into the environment for each request. These can provide a
        communication channel with the application.
    :type extra_environ:
        dict
    :param relative_to:
        A directory used for file
        uploads are calculated relative to this.  Also ``config:``
        URIs that aren't absolute.
    :type relative_to:
        string
    :param cookiejar:
        :class:`cookielib.CookieJar` alike API that keeps cookies
        across requests.
    :type cookiejar:
        CookieJar instance

    .. attribute:: cookies

        A convenient shortcut for a dict of all cookies in
        ``cookiejar``.

    :param parser_features:
        Passed to BeautifulSoup when parsing responses.
    :type parser_features:
        string or list
    :param json_encoder:
        Passed to json.dumps when encoding json
    :type json_encoder:
        A subclass of json.JSONEncoder
    :param lint:
        If True (default) then check that the application is WSGI compliant
    :type lint:
        A boolean
    NTc	             C   s  dt jkrt jd }t|tr|dryddlm}	 W n tk
rT   tdY nX d|krf|d7 }|dd\}
}|	|
|d	}ndd
l	m
} |||d}|| _|| _|| _|d kri }|| _|| _|d krtjt d}|| _|d krd}|| jj_|d krtj}|| _d S )NZWEBTEST_TARGET_URLhttpr   )	HostProxyzaUsing webtest with a real url requires WSGIProxy2. Please install it with: pip install WSGIProxy2#z#httplib   )client)loadapp)relative_to)policyzhtml.parser)osenvironr   r   
startswithZ	wsgiproxyr2   ImportErrorsplitZpaste.deployr6   appr   r7   extra_environuse_unicoder	   	CookieJarr(   	cookiejarRequestClassr0   parser_featuresjsonJSONEncoder)r    r>   r?   r7   r@   rB   rD   Zjson_encoderr   r2   urlr5   r6   r   r   r$   r      s>    





zTestApp.__init__c             C   s   | j S )a   Allow to set the HTTP_AUTHORIZATION environ key. Value should look
        like one of the following:

        * ``('Basic', ('user', 'password'))``
        * ``('Bearer', 'mytoken')``
        * ``('JWT', 'myjwt')``

        If value is None the the HTTP_AUTHORIZATION is removed
        )authorization_value)r    r   r   r$   get_authorization   s    
zTestApp.get_authorizationc             C   s   || _ |d k	rd}t|ttfrt|dkr|\}}|dkrx|rxt|ttfrxdt|}tt| }|	d}n,|dkr|rt|t
tfr| }nt|t
d||f }nt|| jd|i nd| jkr| jd= d S )	NzfYou should use a value like ('Basic', ('user', 'password')) OR ('Bearer', 'token') OR ('JWT', 'token')   ZBasic:latin1)ZBearerZJWTz%s %sZHTTP_AUTHORIZATION)rH   r   listtuplelenjoinr   r   stripr   strr   
ValueErrorr?   update)r    valueZinvalid_valueZauthtypevalr   r   r$   set_authorization   s(    

zTestApp.set_authorizationc             C   s   t dd | jD S )Nc             S   s   g | ]}|j |jfqS r   )namerU   ).0r,   r   r   r$   
<listcomp>   s    z#TestApp.cookies.<locals>.<listcomp>)dictrB   )r    r   r   r$   cookies   s    zTestApp.cookiesc             C   sp   | j dd}|ddd }d|kr.d| }t|}tjd||dd	|d
d	dd
d	dd	dddd}| j| dS )zD
        Sets a cookie to be passed through with requests.

        Z	HTTP_HOSTz
.localhostrK   r4   r   .z%s.localNFT/)versionrX   rU   portport_specifiedr)   domain_specifieddomain_initial_dotpathpath_specifiedsecureexpiresdiscardcommentcomment_urlrest)r?   getr=   r   r	   CookierB   
set_cookie)r    rX   rU   Zcookie_domainr,   r   r   r$   rn      s.    zTestApp.set_cookiec             C   s   | j   dS )zc
        Resets the state of the application; currently just clears
        saved cookies.
        N)rB   clear)r    r   r   r$   reset  s    zTestApp.resetc             C   s   || j j_dS )zx
        Changes the parser used by BeautifulSoup. See its documentation to
        know the supported parsers.
        N)rC   r0   rD   )r    rD   r   r   r$   set_parser_features  s    zTestApp.set_parser_featuresFc       
      C   s   |  |}t|}| |}|r,t||}td|krR|tdd\}|d< ntd|d< | j||}	|rz| |}|r|	j	
| | j|	||dS )a  
        Do a GET request given the url path.

        :param params:
            A query string, or a dictionary that will be encoded
            into a query string.  You may also include a URL query
            string on the ``url``.
        :param headers:
            Extra headers to send.
        :type headers:
            dictionary
        :param extra_environ:
            Environmental variables that should be added to the request.
        :type extra_environ:
            dictionary
        :param status:
            The HTTP status code you expect in response (if not 200 or 3xx).
            You can also use a wildcard, like ``'3*'`` or ``'*'``.
        :type status:
            integer or string
        :param expect_errors:
            If this is False, then if anything is written to
            environ ``wsgi.errors`` it will be an error.
            If it is True, then non-200/3xx responses are also okay.
        :type expect_errors:
            boolean
        :param xhr:
            If this is true, then marks response as ajax. The same as
            headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }
        :type xhr:
            boolean

        :returns: :class:`webtest.TestResponse` instance.

        ?r4   QUERY_STRING )statusexpect_errors)_make_environrR   _remove_fragmentr   build_paramsr=   rC   blank_add_xhr_headerheadersrT   
do_request)
r    rG   paramsr|   r?   ru   rv   xhrr:   reqr   r   r$   rl     s    %


zTestApp.getrt   c
       
      C   s*   |	r|  |}| jd||||||||d	S )a(  
        Do a POST request. Similar to :meth:`~webtest.TestApp.get`.

        :param params:
            Are put in the body of the request. If params is an
            iterator, it will be urlencoded. If it is a string, it will not
            be encoded, but placed in the body directly.

            Can be a :class:`python:collections.OrderedDict` with
            :class:`webtest.forms.Upload` fields included::

                app.post('/myurl', collections.OrderedDict([
                    ('textfield1', 'value1'),
                    ('uploadfield', webapp.Upload('filename.txt', 'contents'),
                    ('textfield2', 'value2')])))

        :param upload_files:
            It should be a list of ``(fieldname, filename, file_content)``.
            You can also use just ``(fieldname, filename)`` and the file
            contents will be read from disk.
        :type upload_files:
            list
        :param content_type:
            HTTP content type, for example `application/json`.
        :type content_type:
            string

        :param xhr:
            If this is true, then marks response as ajax. The same as
            headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }
        :type xhr:
            boolean

        :returns: :class:`webtest.TestResponse` instance.

        POST)r~   r|   r?   ru   upload_filesrv   content_type)r{   _gen_request)
r    rG   r~   r|   r?   ru   r   rv   r   r   r   r   r$   postJ  s    '
zTestApp.postc
       
      C   s*   |	r|  |}| jd||||||||d	S )z
        Do a PUT request. Similar to :meth:`~webtest.TestApp.post`.

        :returns: :class:`webtest.TestResponse` instance.

        PUT)r~   r|   r?   ru   r   rv   r   )r{   r   )
r    rG   r~   r|   r?   ru   r   rv   r   r   r   r   r$   puty  s    	
zTestApp.putc
       
      C   s*   |	r|  |}| jd||||||||d	S )z
        Do a PATCH request. Similar to :meth:`~webtest.TestApp.post`.

        :returns: :class:`webtest.TestResponse` instance.

        PATCH)r~   r|   r?   ru   r   rv   r   )r{   r   )
r    rG   r~   r|   r?   ru   r   rv   r   r   r   r   r$   patch  s    	
zTestApp.patchc	       	      C   s*   |r|  |}| jd|||||d||d	S )z
        Do a DELETE request. Similar to :meth:`~webtest.TestApp.get`.

        :returns: :class:`webtest.TestResponse` instance.

        DELETEN)r~   r|   r?   ru   r   rv   r   )r{   r   )	r    rG   r~   r|   r?   ru   rv   r   r   r   r   r$   delete  s    	
zTestApp.deletec          	   C   s&   |r|  |}| jd||||d|dS )z
        Do a OPTIONS request. Similar to :meth:`~webtest.TestApp.get`.

        :returns: :class:`webtest.TestResponse` instance.

        OPTIONSN)r|   r?   ru   r   rv   )r{   r   )r    rG   r|   r?   ru   rv   r   r   r   r$   options  s    

zTestApp.optionsc          	   C   s6   |rt ||}|r| |}| jd||||d|dS )z
        Do a HEAD request. Similar to :meth:`~webtest.TestApp.get`.

        :returns: :class:`webtest.TestResponse` instance.

        HEADN)r|   r?   ru   r   rv   )r   ry   r{   r   )r    rG   r~   r|   r?   ru   rv   r   r   r   r$   head  s    

zTestApp.headr   r   r   r   c       	         s  t tt dd  d  d  g  fdd}x6|D ],\}}t|trry|d}W n    Y nX t|tjr|jr||gt	|j  n||ddg q@t|tj
r||jg}|jdk	r||j |jdk	r||j || q@t|trt|d	}n>t|tr*|d	}n&t|ttfsPtd
|t||d  d| d d|g q@W x|D ]}|| qxW d  d dg d} d d  }||fS )z
        Encodes a set of parameters (typically a name/value list) and
        a set of files (a list of (name, filename, file_body, mimetype)) into a
        typical POST body, returning the (content_type, body).

        rJ   Ns   ----------a_BoUnDaRy   $c                s    | \}}}}t|tr:y|d}W n    Y nX t|trby|d}W n    Y nX |szt|dd }t|}|pd}d  d| d | d d	| d
|g d S )Nasciir   r   s   application/octet-streams   --s&   Content-Disposition: form-data; name="s   "; filename="   "s   Content-Type:     )	_get_file_infor   r   encode	mimetypes
guess_typer   r   extend)	file_infokeyfilenamerU   Zfcontent)boundarylinesr    r   r$   _append_file  s&    

z.TestApp.encode_multipart.<locals>._append_filer   r   r   zCValue for field {0} is a {1} ({2}). It must be str, bytes or an ints   --s&   Content-Disposition: form-data; name="r   s   
z multipart/form-data; boundary=%s)r   rR   randomr   r   r   r   FilerU   rM   Uploadr   contentappendr   intbytesrS   formattyper   rP   r   )	r    r~   filesr   r   rU   r   r   r   r   )r   r   r    r$   encode_multipart  sP    








zTestApp.encode_multipartc       
      K   s   t |trt|}x*| D ]\}}t |trt|||< qW t |trZ| jj|f|}n*| }x | D ]\}}	t|||	 qlW d|j	d< x$| j
 D ]\}}	|j	||	 qW | j|||dS )a  
        Creates and executes a request. You may either pass in an
        instantiated :class:`TestRequest` object, or you may pass in a
        URL and keyword arguments to be passed to
        :meth:`TestRequest.blank`.

        You can use this to run a request without the intermediary
        functioning of :meth:`TestApp.get` etc.  For instance, to
        test a WebDAV method::

            resp = app.request('/new-col', method='MKCOL')

        Note that the request won't have a body unless you specify it,
        like::

            resp = app.request('/test.txt', method='PUT', body='test')

        You can use :class:`webtest.TestRequest`::

            req = webtest.TestRequest.blank('/url/', method='GET')
            resp = app.do_request(req)

        Tzpaste.throw_errors)ru   rv   )r   r   rR   itemsr   rC   rz   copysetattrr:   r?   
setdefaultr}   )
r    Z
url_or_reqru   rv   Z
req_paramskvr   rX   rU   r   r   r$   r-     s     



zTestApp.requestc       
      C   sT  t  }||jd< |jdd}|rB|j|rB|jt|d |_d|jd< i |jd< | jt	| | j
rzt
| jn| j}|j|dd}|  | j|_||_||_| |_y
|j W n tk
r   Y nX | |_x>|jd  D ],\}}	t||r
td	| t|||	 qW |s6| || | | | jt|t	| |S )
a  
        Executes the given webob Request (``req``), with the expected
        ``status``.  Generally :meth:`~webtest.TestApp.get` and
        :meth:`~webtest.TestApp.post` are used instead.

        To use this::

            req = webtest.TestRequest.blank('url', ...args...)
            resp = app.do_request(req)

        .. note::

            You can pass any keyword arguments to
            ``TestRequest.blank()``, which will be set on the request.
            These can be arguments like ``content_type``, ``accept``, etc.

        zwsgi.errorsZSCRIPT_NAMErt   NTzpaste.testingzpaste.testing_variables)Zcatch_exc_infozopaste.testing_variables contains the variable %r, but the response object already has an attribute by that name)r   r:   rl   Z	path_infor;   rO   rB   add_cookie_headerr   Z_RequestCookieAdapterr   Z
middlewarer>   Zget_responsedecode_contentr@   Z_use_unicoder-   Ztest_appr   	TypeErrorgetvalueerrorsr   hasattrrS   r   _check_status_check_errorsextract_cookiesZ_ResponseCookieAdapter)
r    r   ru   rv   r   script_namer>   resrX   rU   r   r   r$   r}   K  s@    





zTestApp.do_requestc             C   s   |dkrd S |j }t|tr>d|kr>tt||tjr>d S t|trT||krTd S t|tt	fr|j
|krtd|dtt||jj|d S |d kr|j
dkr|j
dk rd S td||jj|||j
krtd|||d S )N*z*Bad response: %s (not one of %s for %s)
%sz,    i  z7Bad response: %s (not 200 OK or 3xx redirect for %s)
%szBad response: %s (not %s)
%s)ru   r   r   rematchfnmatch	translateIrM   rN   Z
status_intr   rP   maprR   r-   rG   )r    ru   r   Z
res_statusr   r   r$   r     s4    


zTestApp._check_statusc             C   s   |j }|rtd|d S )Nz!Application had errors logged:
%s)r   r   )r    r   r   r   r   r$   r     s    zTestApp._check_errorsc             C   s$   | j  }d|d< |r || |S )NTzpaste.throw_errors)r?   r   rT   )r    r?   r:   r   r   r$   rw     s
    

zTestApp._make_environc             C   s(   t |\}}}}}t ||||dfS )Nrt   )r
   urlsplit
urlunsplit)r    rG   schemenetlocrd   queryfragmentr   r   r$   rx     s    zTestApp._remove_fragmentc
             C   sj  |  |}
g }t|ts"t|dr.t| }t|ttfrJdd |D }t|dkrt| ||pbd\}	}|	|
d< nbt	
||	}|s|	rt|	drtj|dd	}| ||pd\}	}|	|
d< n|r|
dtd
 |	dk	r|	|
d< t||
d< t|}| |}| j||
}t|tr0||jp,d}t||jd< t||_|rZ|j| | j|||dS )z'
        Do a generic request.
        r   c             S   s&   g | ]\}}t |tjtjfr|qS r   )r   r   r   r   )rY   r   r   r   r   r$   rZ     s    z(TestApp._gen_request.<locals>.<listcomp>r   r   CONTENT_TYPEs	   multipartT)keep_blank_valuesz!application/x-www-form-urlencodedNREQUEST_METHODr   z
wsgi.input)ru   rv   )rw   r   r[   r   rM   r   rN   rO   r   r   Zencode_paramsr   r;   r
   	parse_qslr   rR   rx   rC   rz   r   r   r   r   r:   content_lengthr|   rT   r}   )r    methodrG   r~   r|   r?   ru   r   rv   r   r:   Zinline_uploadsr   r   r   r$   r     sF    





zTestApp._gen_requestc             C   s   t |dkrT|d }| jr*tj| j|}t|d}| }|  |d ||d fS dt |  krldkrn nD|d }t|t	st
dt	t|f t |dkrt|d S |S nt
d	t|d d
  d S )NrJ   r4   rbr         zFile content must be %s not %s)Nzupload_files need to be a list of tuples of (fieldname, filename, filecontent, mimetype) or (fieldname, filename, filecontent) or (fieldname, filename); you gave: %rd   )rO   r7   r9   rd   rP   openreadcloser   r   rS   r   rN   r   )r    r   r   fr   r   r   r$   r     s&    

zTestApp._get_file_infoc             C   s   | pi } |  dtdi | S )NzX-REQUESTED-WITHZXMLHttpRequest)rT   rR   )r|   r   r   r$   r{     s    zTestApp._add_xhr_header)NNTNNNT)NNNNFF)rt   NNNNFNF)rt   NNNNFNF)rt   NNNNFNF)rt   NNNFNF)NNNFF)NNNNFF)NF)NN)N)(r%   r&   r'   r/   r   rC   r   rI   rW   propertyauthorizationr\   rn   rp   rq   rl   r   r   r   r   r   r   r   Zjson_methodZ	post_jsonZput_jsonZ
patch_jsonZdelete_jsonr   r-   r}   r   r   rw   rx   Z	NoDefaultr   r   staticmethodr{   r   r   r   r$   r   X   s^   4  
'
 
5  
-  
  
  
 
 




M
,
G
1)'r/   
__future__r   r9   r   rE   r   r   r   base64r   sixr   r   r   r   r   Z	six.movesr	   Zwebtest.compatr
   r   r   Zwebtest.responser   Zwebtestr   r   r   r   __all__r   r   r*   r(   ZBaseRequestr   objectr   r   r   r   r$   <module>	   s6   