B
    Wc*              	   @   s  d 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mZ ddlmZ ddlmZ ddlmZ ddlmZ edZee
d dddZeddeeeee f  dddd Z ee	def eeed!d"d Z d.ee	def  eeedef d!d#d Z ed/ddeee! eee! df f eeeee f  d$d%d&d'Z"eeee! eee! df f e	def eeed(d)d'Z"e!fddeee! eee! df f eeeeee f  eed$ef d*d+d'Z"G d,d dej#Z$eG d-d$ d$e$Z%dS )0z/Record warnings during test function execution.    N)pformat)TracebackType)Any)Callable)	Generator)Iterator)List)Optional)Pattern)Tuple)Type)TypeVar)Union)final)overload)check_ispytest)WARNS_NONE_ARG)fixture)failT)WarningsRecorderNN)returnc           	   c   s.   t dd} |  td | V  W dQ R X dS )zReturn a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.

    See https://docs.pytest.org/en/latest/how-to/capture-warnings.html for information
    on warning categories.
    T)	_ispytestdefaultN)r   warningssimplefilter)Zwrec r   .lib/python3.7/site-packages/_pytest/recwarn.pyrecwarn   s    

r   .)matchr   )r   r   c             C   s   d S )Nr   )r   r   r   r   deprecated_call*   s    r    )funcargskwargsr   c             O   s   d S )Nr   )r!   r"   r#   r   r   r   r    1   s    c             O   s*   d}| dk	r| f| }t ttff||S )a  Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning``.

    This function can be used as a context manager::

        >>> import warnings
        >>> def api_call_v2():
        ...     warnings.warn('use v3 of this api', DeprecationWarning)
        ...     return 200

        >>> import pytest
        >>> with pytest.deprecated_call():
        ...    assert api_call_v2() == 200

    It can also be used by passing a function and ``*args`` and ``**kwargs``,
    in which case it will ensure calling ``func(*args, **kwargs)`` produces one of
    the warnings types above. The return value is the return value of the function.

    In the context manager form you may use the keyword argument ``match`` to assert
    that the warning matches a text or regex.

    The context manager produces a list of :class:`warnings.WarningMessage` objects,
    one for each warning raised.
    TN)warnsDeprecationWarningPendingDeprecationWarning)r!   r"   r#   __tracebackhide__r   r   r   r    8   s    
WarningsChecker)expected_warningr   r   c            C   s   d S )Nr   )r)   r   r   r   r   r$   X   s    r$   )r)   r!   r"   r#   r   c             O   s   d S )Nr   )r)   r!   r"   r#   r   r   r   r$   a   s    )r)   r"   r   r#   r   c         	   O   s   d}|s8|r*d t|}td| dt| |ddS |d }t|s`t|dt| dt| dd	 ||d
d |S Q R X dS )a  Assert that code raises a particular class of warning.

    Specifically, the parameter ``expected_warning`` can be a warning class or sequence
    of warning classes, and the code inside the ``with`` block must issue at least one
    warning of that class or classes.

    This helper produces a list of :class:`warnings.WarningMessage` objects, one for
    each warning raised (regardless of whether it is an ``expected_warning`` or not).

    This function can be used as a context manager, which will capture all the raised
    warnings inside it::

        >>> import pytest
        >>> with pytest.warns(RuntimeWarning):
        ...    warnings.warn("my warning", RuntimeWarning)

    In the context manager form you may use the keyword argument ``match`` to assert
    that the warning matches a text or regex::

        >>> with pytest.warns(UserWarning, match='must be 0 or None'):
        ...     warnings.warn("value must be 0 or None", UserWarning)

        >>> with pytest.warns(UserWarning, match=r'must be \d+$'):
        ...     warnings.warn("value must be 42", UserWarning)

        >>> with pytest.warns(UserWarning, match=r'must be \d+$'):
        ...     warnings.warn("this is not here", UserWarning)
        Traceback (most recent call last):
          ...
        Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...

    **Using with** ``pytest.mark.parametrize``

    When using :ref:`pytest.mark.parametrize ref` it is possible to parametrize tests
    such that some runs raise a warning and others do not.

    This could be achieved in the same way as with exceptions, see
    :ref:`parametrizing_conditional_raising` for an example.

    Tz, z5Unexpected keyword arguments passed to pytest.warns: z"
Use context-manager form instead?)
match_exprr   r   z object (type: z) must be callable)r      N)joinsorted	TypeErrorr(   callabletype)r)   r   r"   r#   r'   Zargnamesr!   r   r   r   r$   k   s    .c                   s   e Zd ZdZddedd fddZeed d	d
dZe	ddddZ
ed d	ddZe	d	ddZefee ddddZdd	ddZd d	 fddZeee  ee ee dd fddZ  ZS )r   aF  A context manager to record raised warnings.

    Each recorded warning is an instance of :class:`warnings.WarningMessage`.

    Adapted from `warnings.catch_warnings`.

    .. note::
        ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
        differently; see :ref:`ensuring_function_triggers`.

    F)r   N)r   r   c               s&   t | t jdd d| _g | _d S )NT)recordF)r   super__init___entered_list)selfr   )	__class__r   r   r3      s    zWarningsRecorder.__init__zwarnings.WarningMessage)r   c             C   s   | j S )zThe list of recorded warnings.)r5   )r6   r   r   r   list   s    zWarningsRecorder.list)ir   c             C   s
   | j | S )z Get a recorded warning by index.)r5   )r6   r9   r   r   r   __getitem__   s    zWarningsRecorder.__getitem__c             C   s
   t | jS )z&Iterate through the recorded warnings.)iterr5   )r6   r   r   r   __iter__   s    zWarningsRecorder.__iter__c             C   s
   t | jS )z The number of recorded warnings.)lenr5   )r6   r   r   r   __len__   s    zWarningsRecorder.__len__)clsr   c             C   sF   x.t | jD ] \}}t|j|r| j|S qW d}t|ddS )z>Pop the first recorded warning, raise exception if not exists.Tz not found in warning listN)	enumerater5   
issubclasscategorypopAssertionError)r6   r?   r9   wr'   r   r   r   rC      s
    zWarningsRecorder.popc             C   s   g | j dd< dS )z$Clear the list of recorded warnings.N)r5   )r6   r   r   r   clear   s    zWarningsRecorder.clearc                sD   | j rd}td| dt  }|d k	s0t|| _td | S )NTzCannot enter z twicealways)r4   RuntimeErrorr2   	__enter__rD   r5   r   r   )r6   r'   r5   )r7   r   r   rI      s    

zWarningsRecorder.__enter__)exc_typeexc_valexc_tbr   c                s4   | j sd}td| dt ||| d| _ d S )NTzCannot exit z without entering firstF)r4   rH   r2   __exit__)r6   rJ   rK   rL   r'   )r7   r   r   rM      s
    zWarningsRecorder.__exit__)__name__
__module____qualname____doc__boolr3   propertyr   r8   intr:   r   r<   r>   Warningr   rC   rF   rI   r	   BaseExceptionr   rM   __classcell__r   r   )r7   r   r      s   
c                   s   e Zd Zedfddeeee eee df f  eeee	e f  e
dd fddZeee  ee ee dd fd	d
Z  ZS )r(   NF)r   .)r)   r*   r   r   c               s   t | t jdd d}|d kr6tjtdd d }nZt|trnx&|D ]}t|t	sFt
|t| qFW |}n"t|t	r|f}nt
|t| || _|| _d S )NT)r   z/exceptions must be derived from Warning, not %s   )
stacklevel)r   r2   r3   r   warnr   
isinstancetuplerA   rU   r.   r0   r)   r*   )r6   r)   r*   r   msgZexpected_warning_tupexc)r7   r   r   r3      s     	



zWarningsChecker.__init__)rJ   rK   rL   r   c                s   t  ||| d} fdd}|d kr|d kr|d kr؈ jd k	rt fdd D sxd}td j d|  d n` jd k	rxT D ],}t|j jrt	 j
t|jrP qW td j d	 j d
|   d S )NTc                  s   t dd  D ddS )Nc             S   s   g | ]
}|j qS r   )message).0r1   r   r   r   
<listcomp>#  s    z?WarningsChecker.__exit__.<locals>.found_str.<locals>.<listcomp>   )indent)r   r   )r6   r   r   	found_str"  s    z+WarningsChecker.__exit__.<locals>.found_strc             3   s   | ]}t |j jV  qd S )N)rA   rB   r)   )r`   r)r6   r   r   	<genexpr>(  s    z+WarningsChecker.__exit__.<locals>.<genexpr>z"DID NOT WARN. No warnings of type z0 were emitted.
The list of emitted warnings is: .z* matching the regex were emitted.
 Regex: z
 Emitted warnings: )r2   rM   r)   anyr   r*   rA   rB   recompilesearchstrr_   )r6   rJ   rK   rL   r'   rd   re   )r7   )r6   r   rM     s     


zWarningsChecker.__exit__)rN   rO   rP   rU   r	   r   r   r   rl   r
   rR   r3   rV   r   rM   rW   r   r   )r7   r   r(      s   8
)N).)&rQ   ri   r   Zpprintr   typesr   typingr   r   r   r   r   r	   r
   r   r   r   r   Z_pytest.compatr   r   Z_pytest.deprecatedr   r   Z_pytest.fixturesr   Z_pytest.outcomesr   r   r   rl   r    rU   r$   catch_warningsr   r(   r   r   r   r   <module>   sb   2
4:O