U
    42i3                     @  s  d 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 ddlmZ ddlmZ erd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 edZeddddZedddddddZed d!d!dd"d#dZd3d$d!d!d%d"d&dZed4ddd'dd(d)d*d+Zed'd d!d!dd,d-d+Ze fddd'd!dd!d.d/d0d+ZG d1d dej!Z"eG d2d( d(e"Z#dS )5z/Record warnings during test function execution.    )annotationspformatN)TracebackType)Any)Callable)final)	Generator)Iterator)overload)Pattern)TYPE_CHECKING)TypeVar)Self)check_ispytest)fixture)Exit)failTzGenerator[WarningsRecorder]returnc               	   c  s.   t dd} |  td | V  W 5 Q R X dS )zReturn a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.

    See :ref:`warnings` for information on warning categories.
    T	_ispytestdefaultN)WarningsRecorderwarningssimplefilter)Zwrec r   3/tmp/pip-unpacked-wheel-7n2p7kht/_pytest/recwarn.pyrecwarn"   s    

r   .matchstr | Pattern[str] | Noner   )r!   r   c                 C  s   d S Nr   r    r   r   r   deprecated_call.   s    r$   zCallable[..., T]r   )funcargskwargsr   c                 O  s   d S r#   r   )r%   r&   r'   r   r   r   r$   2   s    zCallable[..., Any] | NonezWarningsRecorder | Anyc                 O  s,   d}| dk	r| f|}t tttff||S )a  Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning`` or ``FutureWarning``.

    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FutureWarning)r%   r&   r'   __tracebackhide__r   r   r   r$   6   s    
)type[Warning] | tuple[type[Warning], ...]WarningsChecker)expected_warningr!   r   c                C  s   d S r#   r   )r/   r!   r   r   r   r(   X   s    r(   )r/   r%   r&   r'   r   c                 O  s   d S r#   r   )r/   r%   r&   r'   r   r   r   r(   `   s    zWarningsChecker | Any)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 |W  5 Q R  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 tuple
    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 emitted (regardless of whether it is an ``expected_warning`` or not).
    Since pytest 8.0, unmatched warnings are also re-emitted when the context closes.

    This function can be used as a context manager::

        >>> 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):  # catch re-emitted warning
        ...     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 callabler      N)joinsorted	TypeErrorr.   callabletype)r/   r!   r&   r'   r,   argnamesr%   r   r   r   r(   i   s    /
c                      s   e Zd ZdZddddd fddZed	d
ddZdddddZdd
ddZdd
ddZ	e
fdddddZdd
ddZdd
 fddZd d!d"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`.

    Fr   boolNone)r   r   c                  s&   t | t jdd d| _g | _d S )NT)recordF)r   super__init___entered_list)selfr   	__class__r   r   r<      s    zWarningsRecorder.__init__zlist[warnings.WarningMessage]r   c                 C  s   | j S )zThe list of recorded warnings.r>   r?   r   r   r   list   s    zWarningsRecorder.listintwarnings.WarningMessage)ir   c                 C  s
   | j | S )z Get a recorded warning by index.rB   )r?   rG   r   r   r   __getitem__   s    zWarningsRecorder.__getitem__z!Iterator[warnings.WarningMessage]c                 C  s
   t | jS )z&Iterate through the recorded warnings.)iterr>   rC   r   r   r   __iter__   s    zWarningsRecorder.__iter__c                 C  s
   t | jS )z The number of recorded warnings.)lenr>   rC   r   r   r   __len__   s    zWarningsRecorder.__len__ztype[Warning])clsr   c                 C  s   d}t | jD ]N\}}|j|kr0| j|  S t|j|r|dksXt|j| j| js|}q|dk	rr| j|S d}t|ddS )zPop the first recorded warning which is an instance of ``cls``,
        but not an instance of a child class of any other match.
        Raises ``AssertionError`` if there is no match.
        NTz not found in warning list)	enumerater>   categorypop
issubclassAssertionError)r?   rM   Zbest_idxrG   wr,   r   r   r   rP      s    
zWarningsRecorder.popc                 C  s   g | j dd< dS )z$Clear the list of recorded warnings.NrB   rC   r   r   r   clear   s    zWarningsRecorder.clearr   c                   sD   | j rd}td| dt  }|d k	s0t|| _td | S )NTzCannot enter z twicealways)r=   RuntimeErrorr;   	__enter__rR   r>   r   r   )r?   r,   r>   r@   r   r   rW      s    

zWarningsRecorder.__enter__type[BaseException] | NoneBaseException | NoneTracebackType | None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)r=   rV   r;   __exit__)r?   r\   r]   r^   r,   r@   r   r   r_      s
    zWarningsRecorder.__exit__)__name__
__module____qualname____doc__r<   propertyrD   rH   rJ   rL   WarningrP   rT   rW   r_   __classcell__r   r   r@   r   r      s   c                      s\   e Zd Zedfddddddd fd	d
ZdddddZddddd fddZ  ZS )r.   NFr   r-   r"   r8   r9   )r/   r0   r   r   c                  s   t | t jdd d}t|trN|D ]}t|ts(t|t| q(|}n,t|trjt|trj|f}nt|t| || _	|| _
d S )NTr   z/exceptions must be derived from Warning, not %s)r   r;   r<   
isinstancetuplerQ   re   r4   r6   r/   r0   )r?   r/   r0   r   msgexcZexpected_warning_tupr@   r   r   r<     s     

 zWarningsChecker.__init__rF   )warningr   c                 C  s>   | j d k	stt|j| j o<t| jd kp:t| jt|j	S r#   )
r/   rR   rQ   rO   r8   r0   researchstrmessage)r?   rk   r   r   r   matches  s    zWarningsChecker.matchesrX   rY   rZ   r[   c                   sP  t  ||| d}|d k	r4t|tr0t|tr4d S dd fdd}znt fdd D sztd j d|  d n8t fdd D std j d j d|  d W 5  D ]0} |stj|j|j	|j
|j|j|jd q D ]X}t|jtk	rq|jjsq|jjd }t|tr,qtd|d	t|j d
qX d S )NTrn   r   c                     s   t dd  D ddS )Nc                 S  s   g | ]
}|j qS r   )ro   ).0r:   r   r   r   
<listcomp>8  s     z?WarningsChecker.__exit__.<locals>.found_str.<locals>.<listcomp>   )indentr   r   rC   r   r   	found_str7  s    z+WarningsChecker.__exit__.<locals>.found_str)ro   rO   filenamelinenomodulesourcer   z$Warning must be str or Warning, got z (type )c                 3  s   | ]}t |j jV  qd S r#   )rQ   rO   r/   rq   rS   rC   r   r   	<genexpr>;  s     z+WarningsChecker.__exit__.<locals>.<genexpr>z"DID NOT WARN. No warnings of type z" were emitted.
 Emitted warnings: .c                 3  s   | ]}  |V  qd S r#   )rp   r{   rC   r   r   r|   @  s     z* matching the regex were emitted.
 Regex: z
 Emitted warnings: )r;   r_   rg   	Exceptionr   rp   r   warn_explicitro   rO   rv   rw   ra   ry   r6   UserWarningr&   rn   r4   r`   anyr   r/   r0   )r?   r\   r]   r^   r,   ru   rS   ri   r@   rC   r   r_   "  sN    

zWarningsChecker.__exit__)r`   ra   rb   re   r<   rp   r_   rf   r   r   r@   r   r.      s   )N).)$rc   
__future__r   pprintr   rl   typesr   typingr   r   r   r	   r
   r   r   r   r   Ztyping_extensionsr   r   Z_pytest.deprecatedr   Z_pytest.fixturesr   Z_pytest.outcomesr   r   r   r   r$   r(   re   catch_warningsr   r.   r   r   r   r   <module>   sV    " 	@W