3
¥YðiX*  ã               @   sê   d dl Zd dlmZ d dlmZ d dlm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 ejr²d dlmZ d	dlmZ G dd„ dejjƒZG dd„ deƒZ G dd„ de
ƒZ!dS )é    N)Úcontextmanager)Úcopy)ÚTracebackType)Ú	CliRunner)ÚClient)Ú	url_parse)ÚRequesté   )Ú
ScriptInfo)Ú_request_ctx_stack)Údumps)ÚSessionMixin)ÚTestResponse)ÚFlaskc            
       sb   e Zd ZdZddeeje eje eje ejejddœ‡ fdd„Zejejedœd	d
„Z	‡  Z
S )ÚEnvironBuildera½  An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the
    application.

    :param app: The Flask application to configure the environment from.
    :param path: URL path being requested.
    :param base_url: Base URL where the app is being served, which
        ``path`` is relative to. If not given, built from
        :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
        :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
    :param subdomain: Subdomain name to append to :data:`SERVER_NAME`.
    :param url_scheme: Scheme to use instead of
        :data:`PREFERRED_URL_SCHEME`.
    :param json: If given, this is serialized as JSON and passed as
        ``data``. Also defaults ``content_type`` to
        ``application/json``.
    :param args: other positional arguments passed to
        :class:`~werkzeug.test.EnvironBuilder`.
    :param kwargs: other keyword arguments passed to
        :class:`~werkzeug.test.EnvironBuilder`.
    ú/Nr   )ÚappÚpathÚbase_urlÚ	subdomainÚ
url_schemeÚargsÚkwargsÚreturnc                sì   |p
|p
| s*|d k	t |p|ƒks*tdƒ‚|d krÌ|jjdƒp@d}|jd }	|r^|› d|› �}|d krp|jd }t|ƒ}
|
jp€|› d|
jpŒ|› d|	jdƒ› �}|
j}|
j	rÌt
|
j	tƒrºd	nd
}|||
j	 7 }|| _tƒ j||f|ž|Ž d S )Nz8Cannot pass "subdomain" or "url_scheme" with "base_url".ZSERVER_NAMEÚ	localhostZAPPLICATION_ROOTÚ.ZPREFERRED_URL_SCHEMEz://r   ó   ?ú?)ÚboolÚAssertionErrorÚconfigÚgetr   ÚschemeÚnetlocÚlstripr   ÚqueryÚ
isinstanceÚbytesr   ÚsuperÚ__init__)Úselfr   r   r   r   r   r   r   Z	http_hostZapp_rootÚurlÚsep)Ú	__class__© ú./tmp/pip-build-8om4l6ph/flask/flask/testing.pyr)   -   s(    


&zEnvironBuilder.__init__)Úobjr   r   c             K   s   |j d| jƒ t|f|ŽS )z³Serialize ``obj`` to a JSON-formatted string.

        The serialization will be configured according to the config associated
        with this EnvironBuilder's ``app``.
        r   )Ú
setdefaultr   Ú
json_dumps)r*   r0   r   r.   r.   r/   r2   U   s    zEnvironBuilder.json_dumps)r   NNN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚtÚOptionalÚAnyr)   r2   Ú__classcell__r.   r.   )r-   r/   r      s      r   c                   s¦   e Zd ZU dZddZejejddœ‡ fdd„Ze	ejejej
eddf dœdd	„ƒZddd
œejeeejddœ‡ fdd„Zd dœdd„Zeeeddœdd„Z‡  ZS )ÚFlaskClientaE  Works like a regular Werkzeug test client but has some knowledge about
    how Flask works to defer the cleanup of the request context stack to the
    end of a ``with`` body when used in a ``with`` statement.  For general
    information about how to use this class refer to
    :class:`werkzeug.test.Client`.

    .. versionchanged:: 0.12
       `app.test_client()` includes preset default environment, which can be
       set after instantiation of the `app.test_client()` object in
       `client.environ_base`.

    Basic usage is outlined in the :doc:`/testing` chapter.
    r   FN)r   r   r   c                s&   t ƒ j||Ž ddtj› �dœ| _d S )Nz	127.0.0.1z	werkzeug/)ZREMOTE_ADDRZHTTP_USER_AGENT)r(   r)   ÚwerkzeugÚ__version__Úenviron_base)r*   r   r   )r-   r.   r/   r)   q   s    zFlaskClient.__init__c             o   sÖ   | j dkrtdƒ‚| j}|jdi ƒ}| j j|ƒ tj}|j||Ž�Š}|j}|j	||j
ƒ}|dkrhtdƒ‚tj|ƒ z
|V  W dtjƒ  X |jƒ }	|j|ƒs¨|j|||	ƒ |	j|j
jƒ}
| j j|j
j|
ƒ W dQ R X dS )a’  When used in combination with a ``with`` statement this opens a
        session transaction.  This can be used to modify the session that
        the test client uses.  Once the ``with`` block is left the session is
        stored back.

        ::

            with client.session_transaction() as session:
                session['value'] = 42

        Internally this is implemented by going through a temporary test
        request context and since session handling could depend on
        request variables this function accepts the same arguments as
        :meth:`~flask.Flask.test_request_context` which are directly
        passed through.
        Nz:Session transactions only make sense with cookies enabled.Úenviron_overridesz?Session backend did not open a session. Check the configuration)Z
cookie_jarÚRuntimeErrorÚapplicationr1   Zinject_wsgir   ÚtopZtest_request_contextÚsession_interfaceZopen_sessionÚrequestÚpushÚpopÚresponse_classZis_null_sessionZsave_sessionZget_wsgi_headersÚenvironZextract_wsgi)r*   r   r   r   r@   Zouter_reqctxÚcrD   ÚsessÚrespÚheadersr.   r.   r/   Úsession_transactionx   s,    





zFlaskClient.session_transaction)ÚbufferedÚfollow_redirectsr   )r   rO   rP   r   r   c               s<  |j dd ƒ}d }‡ fdd„}| rªt|ƒdkrª|d }t|tjjƒrft|ƒ}	||	jpVi ƒ|	_|	jƒ }nDt|t	ƒrŒtj
|ˆ j|i ƒd�jƒ }nt|tƒrªt|ƒ}||jƒ|_|d krð||jdi ƒƒ|d< tˆ jf|ž|Ž}	z|	jƒ }W d |	jƒ  X |d k	�r&dd l}
|
jdtd	d
� tƒ j||||d�S tƒ j|||d�S d S )NÚas_tuplec                s   ˆ j | dˆ ji–S )Nzflask._preserve_context)r?   Úpreserve_context)Úother)r*   r.   r/   Úcopy_environ»   s    z&FlaskClient.open.<locals>.copy_environr	   r   )r   r?   r?   zs'as_tuple' is deprecated and will be removed in Werkzeug 2.1 and Flask 2.1. Use 'response.request.environ' instead.é   )Ú
stacklevel)rQ   rO   rP   )rO   rP   )rG   Úlenr&   r=   Útestr   r   r?   Úget_requestÚdictZfrom_environrB   ÚBaseRequestrI   r!   ÚcloseÚwarningsÚwarnÚDeprecationWarningr(   Úopen)r*   rO   rP   r   r   rQ   rE   rT   ÚargZbuilderr]   )r-   )r*   r/   r`   ¯   sH    




zFlaskClient.open)r   c             C   s   | j rtdƒ‚d| _ | S )NzCannot nest client invocationsT)rR   rA   )r*   r.   r.   r/   Ú	__enter__ñ   s    zFlaskClient.__enter__)Úexc_typeÚ	exc_valueÚtbr   c             C   s0   d| _ x$tj}|d k	r&|jr&|jƒ  qP qW d S )NF)rR   r   rC   Z	preservedrG   )r*   rc   rd   re   rC   r.   r.   r/   Ú__exit__÷   s    
zFlaskClient.__exit__)r3   r4   r5   r6   rB   rR   r8   r:   r)   r   Ú	Generatorr   rN   r   r`   rb   ÚtypeÚBaseExceptionr   rf   r;   r.   r.   )r-   r/   r<   _   s   
7<r<   c                   sN   e Zd ZdZdejddœ‡ fdd„Zd
ejejejejdœ‡ fdd	„Z‡  ZS )ÚFlaskCliRunnerz®A :class:`~click.testing.CliRunner` for testing a Flask app's
    CLI commands. Typically created using
    :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`.
    r   N)r   r   r   c                s   || _ tƒ jf |Ž d S )N)r   r(   r)   )r*   r   r   )r-   r.   r/   r)     s    zFlaskCliRunner.__init__)Úclir   r   r   c                s@   |dkrˆ j j}d|kr.t‡ fdd„d�|d< tƒ j||f|ŽS )ac  Invokes a CLI command in an isolated environment. See
        :meth:`CliRunner.invoke <click.testing.CliRunner.invoke>` for
        full method documentation. See :ref:`testing-cli` for examples.

        If the ``obj`` argument is not given, passes an instance of
        :class:`~flask.cli.ScriptInfo` that knows how to load the Flask
        app being tested.

        :param cli: Command object to invoke. Default is the app's
            :attr:`~flask.app.Flask.cli` group.
        :param args: List of strings to invoke the command with.

        :return: a :class:`~click.testing.Result` object.
        Nr0   c                  s   ˆ j S )N)r   r.   )r*   r.   r/   Ú<lambda>(  s    z'FlaskCliRunner.invoke.<locals>.<lambda>)Z
create_app)r   rk   r
   r(   Úinvoke)r*   rk   r   r   )r-   )r*   r/   rm     s
    zFlaskCliRunner.invoke)NN)	r3   r4   r5   r6   r8   r:   r)   rm   r;   r.   r.   )r-   r/   rj   	  s   rj   )"Útypingr8   Ú
contextlibr   r   Útypesr   Zwerkzeug.testr=   Zclick.testingr   r   Zwerkzeug.urlsr   Zwerkzeug.wrappersr   r[   rk   r
   Úglobalsr   Újsonr   r2   Úsessionsr   ZTYPE_CHECKINGr   r   r   rX   r   r<   rj   r.   r.   r.   r/   Ú<module>   s&   H +