
    ^j(                     v   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mZmZmZ ded	eeeeef      fd
Z ed      ded	ej(                  fd       Zded	ej(                  fdZdeej.                     d	eeeef      fdZeddeee      dee   d	efd       Z G d d      Zdeded	efdZy)u  Low-level helpers for the deprecation system.

This module provides two kinds of helpers:

**Internal** (used by :mod:`deprecate.deprecation` and :mod:`deprecate.audit`):
    - :func:`~deprecate.utils.get_func_arguments_types_defaults`: Extract parameter names, annotations, and defaults
      from a callable's signature. Used when applying ``args_mapping`` and when auditing wrapper configuration.

**Public — decorator companion** (exported via :mod:`deprecate`):
    - :func:`~deprecate.utils.void`: Accepts any arguments and returns ``None``. Used in deprecated function stubs
      to satisfy IDEs and mypy about unused parameters.

**Public — testing** (exported via :mod:`deprecate`):
    - :func:`~deprecate.utils.assert_no_warnings`: Context manager that asserts no warnings are raised during a
      block — the inverse of ``pytest.warns()``.

Copyright (C) 2020-2026 Jiri Borovec <6035284+Borda@users.noreply.github.com>

    N)	Generator)contextmanager)	lru_cache)TracebackType)AnyCallableOptionalUnionfuncreturnc                     t        |       j                  }g }|D ]4  }||   j                  }||   j                  }|j	                  |||f       6 |S )a0  Parse function arguments, types and default values.

    This introspection helper extracts the complete signature information from a function, including parameter names,
    type annotations, and default values.  Useful for dynamic argument handling and validation in wrapper functions.

    Args:
        func: A function to be examined.

    Returns:
        List of tuples, one per argument, each containing:
            - str: argument name
            - Any: argument type annotation (or inspect.Parameter.empty if no annotation)
            - Any: default value (or inspect.Parameter.empty if no default)

    Example:
        >>> def example_func(x: int, y: str = "hello", z=42) -> None:
        ...     pass
        >>> result = get_func_arguments_types_defaults(example_func)
        >>> for name, type_hint, default in result:
        ...     print(f"{name}: type={type_hint}, default={default}")
        x: type=<class 'int'>, default=<class 'inspect._empty'>
        y: type=<class 'str'>, default=hello
        z: type=<class 'inspect._empty'>, default=42

    Note:
        - Parameters without type annotations have annotation = inspect.Parameter.empty
        - Parameters without defaults have default = inspect.Parameter.empty
        - Excludes *args and **kwargs (use inspect.getfullargspec for those)

    )_get_signature
parameters
annotationdefaultappend)r   func_default_paramsfunc_arg_type_valargarg_typearg_defaults         Z/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/deprecate/utils.py!get_func_arguments_types_defaultsr      sg    > ).99" ?&s+66)#.66  #x!=>?        )maxsizec                 ,    t        j                  |       S )zCache inspect.signature lookups for repeated calls.

    Uses an LRU cache (maxsize=256) since function signatures are stable at runtime. The size balances reuse for common
    callables without unbounded memory growth.

    )inspect	signaturer   s    r   _get_signature_cachedr!   F   s     T""r   c                 b    	 t        |       S # t        $ r t        j                  |       cY S w xY w)zuGet function signature with caching when possible.

    Falls back to uncached lookup for unhashable callables.

    )r!   	TypeErrorr   r   r    s    r   r   r   Q   s2    '$T** '  &&'s   
 ..warnsc                 @    | D cg c]  }|j                    c}S c c}w )zConvert list of warning messages to their string representations.

    Args:
        warns: List of warning message objects captured during execution.

    Returns:
        List of warning messages as strings or Warning objects.

    )message)r$   ws     r   _warns_reprr(   ]   s      %%!AII%%%s   warning_typematchc              #   N  K   t        j                  d      5 }t        j                  d       d |s
	 ddd       y| st        dt	        |             |D cg c]  }t        |j                  |       s| }}|s
	 ddd       y|s$t        d| j                   dt	        |             |D cg c]!  }||j                  j                         v s |# }}|r't        d| j                   d| d	t	        |             	 ddd       yc c}w c c}w # 1 sw Y   yxY ww)
u  Context manager asserting that no warnings are raised — the inverse of ``pytest.warns()``.

    Useful for testing that refactored code properly avoids deprecated functionality or that new implementations don't
    trigger warnings.

    Args:
        warning_type: The warning type that must NOT be raised (e.g., :class:`FutureWarning`,
            :class:`DeprecationWarning`). If ``None``, asserts that no warnings of any type are raised.
        match: If given, only fail if a warning message contains this string. If ``None``, fails on any warning of
            the specified type.

    Raises:
        AssertionError: If a warning of the specified type (and optionally matching the message pattern) was raised
            during the context.

    Example:
        >>> # Assert new function doesn't trigger FutureWarning
        >>> import warnings
        >>> def new_func(x: int) -> int:
        ...     return x * 2
        >>> with assert_no_warnings(FutureWarning):
        ...     result = new_func(42)
        >>> result
        84

        >>> # Assert NO warnings at all are raised
        >>> def clean_function():
        ...     pass
        >>> with assert_no_warnings():
        ...     clean_function()

        >>> # Only fail if warning message matches pattern
        >>> def some_function():
        ...     warnings.warn("deprecated feature", FutureWarning)
        >>> # Passes because warning contains "feature", not "other"
        >>> with assert_no_warnings(FutureWarning, match="other"):
        ...     some_function()

    Note:
        This context manager is particularly useful in pytest for testing that refactored code properly uses new APIs
        without triggering deprecation warnings.

    T)recordalwaysNz/While catching all warnings, these were found: zWhile catching `z` warnings, these were found: z` warnings with "z", these were found: )
warningscatch_warningssimplefilterAssertionErrorr(   
issubclasscategory__name__r&   __str__)r)   r*   calledr'   r$   founds         r   assert_no_warningsr8   j   sJ    Z 
	 	 	- h'   #RS^_eSfRg!hii"Kqj\&JKK   "<#8#8"99WXcdiXjWkl  "BqUaii.?.?.A%ABB "<#8#8"99J5' R&&1%&8%9;  )  L C' s\   D%D	D%DD8D<D	D%
*D4!DD+D	D%
DD"D%c            	       v    e Zd ZdZddeee      dee   ddfdZddZ	deee
      d	ee
   d
ee   dee   fdZy)no_warning_callu  Deprecated alias for :func:`~deprecate.utils.assert_no_warnings`.

    This context manager is kept for backward compatibility so that existing imports like
    ``from deprecate.utils import no_warning_call`` continue to work until v1.0.

    Warning fires at instantiation — the ``no_warning_call(...)`` call line receives the
    deprecation notice, regardless of how the context manager is subsequently used.

    Args:
        warning_type: The :class:`Warning` subclass to watch for.  Defaults to :class:`Warning`
            (all warning categories).
        match: Optional substring that must appear in the warning message.  When ``None`` (default),
            any warning of the right category triggers an :class:`AssertionError`.

    Examples:
        >>> import warnings
        >>> with warnings.catch_warnings():
        ...     warnings.simplefilter("ignore", DeprecationWarning)
        ...     with no_warning_call():
        ...         pass  # no AssertionError means no warnings were emitted

    Nr)   r*   r   c                 f    t        j                  dt        d       || _        || _        d| _        y)zQEmit the alias-deprecation warning and capture args for the no-warning assertion.z`deprecate.utils.no_warning_call` is deprecated in `0.6` and will be removed in `1.0`; use `deprecate.utils.assert_no_warnings` instead.   )
stacklevelN)r.   warnDeprecationWarning_warning_type_match_inner)selfr)   r*   s      r   __init__zno_warning_call.__init__   s2    @		
 *r   c                     t        | j                  | j                        | _        | j                  j	                          y)z4Enter the underlying ``assert_no_warnings`` context.)r)   r*   N)r8   r@   rA   rB   	__enter__)rC   s    r   rF   zno_warning_call.__enter__   s-    (d6H6HPTP[P[\r   exc_typeexc_valexc_tbc                 X    | j                   J | j                   j                  |||      S )z[Forward exit to the underlying ``assert_no_warnings`` so its AssertionError still surfaces.)rB   __exit__)rC   rG   rH   rI   s       r   rK   zno_warning_call.__exit__   s-     {{&&&{{##Hgv>>r   NN)r   N)r4   
__module____qualname____doc__r	   typeWarningstrrD   rF   BaseExceptionr   boolrK    r   r   r:   r:      sx    .
 Xd7m%< 
 HUXM 
 ei 
  
?4./? -(? '	?
 
$?r   r:   argskwrgsc                      | |c}}y)a  Empty function that accepts any arguments and returns None.

    This helper function is used to silence IDE warnings about unused parameters in deprecated functions where the
    body is never executed (calls are forwarded to a target function). It's purely a convenience for developers.

    Args:
        *args: Any positional arguments (ignored).
        **kwrgs: Any keyword arguments (ignored).

    Returns:
        None always.

    Example:
        >>> from deprecate import deprecated, void
        >>>
        >>> def new_func(x: int) -> int:
        ...     return x * 2
        >>>
        >>> @deprecated(target=new_func, deprecated_in="1.0", remove_in="2.0")
        ... def old_func(x: int) -> int:
        ...     void(x)  # Silences IDE warning about unused 'x'
        ...     # This line is never reached - call forwarded to new_func

    Note:
        This function has no runtime effect - it's purely for developer convenience. You can also use ``pass`` or
        just a docstring instead of calling ``void()``.

    NrU   )rV   rW   _s      r   voidrZ      s    : DAqr   rL   )rO   r   r.   collections.abcr   
contextlibr   	functoolsr   typesr   typingr   r   r	   r
   listtuplerR   r   	Signaturer!   r   WarningMessagerQ   r(   rP   r8   r:   rZ   rU   r   r   <module>rd      s  (   % %   1 1%H %eCcM>R9S %P 3# #W->-> # #	' 	'g&7&7 	'
&tH334 
&eGSL>Q9R 
& DXd7m%< DHUXM Den D DN1? 1?h c c r   