
    ^j]                     .   U d Z ddlZddlZddlZddlZddlmZmZmZ ddl	m
Z
mZmZ g dZg dZdZdZd	Zd
ZdZdddddZ ee      Zee   ed<   h dZh dZdedefdZdee   defdZded   fdZ deded   fdZ!dee   dededefdZ"dee   de#eef   fd Z$dee   d!ed"ede#eef   fd#Z%dee   d!ed"ed$ed%edefd&Z&dee   d'ed(edefd)Z'dee   d%ed*ede#ee   ef   fd+Z(dee   d%ed*ede#ee   ef   fd,Z)d-e
dee   fd.Z*d/e+ddfd0Z,y)1a  Helpers for annotating function docstrings with deprecation information.

This module owns all logic that reads or modifies a callable's ``__doc__``
attribute during deprecation decoration.  It supports both Google-style
(``Args:`` / ``Arguments:``), NumPy-style (``Parameters`` + underline),
and Sphinx-style (``:param ...:``) docstrings, plus MkDocs/Markdown output.

Key Components:
    - String constants (``TEMPLATE_DOC_*``) for reusable message fragments.
    - Style normalizer: :func:`normalize_docstring_style`, :func:`_auto_detect_style`
    - Section-aware insertion helpers: :func:`find_docstring_insertion_index`,
      :func:`is_numpy_underline`
    - Per-argument note builder: :func:`_build_arg_deprecation_note`
    - Google-style section helpers: :func:`_find_google_args_section`,
      :func:`_get_google_arg_indents`, :func:`_find_google_arg_line`
    - Shared continuation-line helper: :func:`_find_entry_end`
    - Annotators: :func:`_annotate_google_style_arg`,
      :func:`_annotate_sphinx_style_arg`
    - Notice builder: :func:`_build_general_notice_lines`
    - Orchestrator: :func:`_update_docstring_with_deprecation`

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

    N)LiteralOptionalcast)DeprecationConfig
TargetMode_has_deprecation_meta)z!.. deprecated:: %(deprecated_in)sz   %(remove_text)sz   %(target_text)s)z-!!! warning "Deprecated in %(deprecated_in)s"z    %(remove_text)sz    %(target_text)su3   Deprecated since v%(deprecated_in)s — %(reason)s.u   Deprecated — %(reason)s.z# Will be removed in v%(remove_in)s.zno longer usedzuse `%(new_arg)s` insteadautorstmkdocs)r	   r
   r   markdownSUPPORTED_DOCSTRING_STYLES>
   args:notes:warns:raises:yields:returns:	examples:
arguments:attributes:parameters:>
   other parametersnoteswarnsraisesyieldsmethodsreturnsexamples
attributes
parameterslinereturnc                 f    | j                         }t        |      dk\  xr t        d |D              S )zAReturn ``True`` when the line is a NumPy-style section underline.   c              3   &   K   | ]	  }|d k(    yw)-N ).0chars     e/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/deprecate/docstring/inject.py	<genexpr>z%is_numpy_underline.<locals>.<genexpr>X   s     %Gddck%Gs   )striplenall)r"   strippeds     r+   is_numpy_underliner1   U   s,    zz|Hx=AG#%Gh%G"GG    linesc                 &   t        |       D ]y  \  }}|j                         j                         t        v r|c S |dz   t	        |       k  s@|j                         j                         t
        v set        | |dz            sw|c S  t	        |       S )z>Find insertion index before first Google/NumPy section header.   )	enumerater-   lowerGOOGLE_DOCSTRING_SECTIONSr.   NUMPY_DOCSTRING_SECTIONSr1   )r3   idxr"   s      r+   find_docstring_insertion_indexr;   [   s    u% 	T::<#<<J!Gc%j 

""$(@@"5q>2J u:r2   r
   r   c                     t         j                  j                  dd      j                         } | dv ry| dk(  rydt        j
                  v ryt        j                  r$dt        j                  d   j                         v ryy)uo  Detect documentation engine from environment or process name.

    Resolution order:

    1. ``DEPRECATE_DOCSTRING_STYLE`` env var — explicit override, takes highest priority.
    2. ``sys.modules`` — ``mkdocs`` imported → MkDocs build in progress.
    3. ``sys.argv[0]`` full path — ``mkdocs`` anywhere in the path string.
    4. Default → ``"rst"``.

    DEPRECATE_DOCSTRING_STYLE )r   r   r   r
   r   )osenvirongetr7   sysmodulesargv)	env_styles    r+   _auto_detect_stylerG   i   sm     

:B?EEGI**E3;;
xxH 1 1 33r2   docstring_stylec                 ,   t        | t              st        d| dt        t              d      t
        j                  | j                               }|t        d| dt        t              d      |dk(  r
t               S t        t        d   |      S )z/Validate and normalize docstring style aliases.z Invalid `docstring_style` value z. Supported styles are: .r	   r<   )
isinstancestr
ValueErrorsortedr   DOCSTRING_STYLE_ALIASESrB   r7   rG   r   r   )rH   normalized_styles     r+   normalize_docstring_stylerQ      s    os+.!!9&A[:\9__`b
 	
 /22?3H3H3JK.!!9&A[:\9__`b
 	
 6!!##(*:;;r2   new_argdeprecated_in	remove_inc                 x    | rt         d| iz  nt        }|rt        nt        }|||dz  }|r|t        d|iz  z  }|S )u  Build an inline deprecation note string for a single deprecated argument.

    Args:
        new_arg: Replacement argument name, or ``None`` when the argument is simply removed.
        deprecated_in: Version string when the argument was deprecated (e.g. ``"1.8"``).
        remove_in: Version string when the argument will be removed (e.g. ``"1.9"``).

    Returns:
        A one-line deprecation note suitable for embedding in a docstring.

    Example:
        >>> _build_arg_deprecation_note(None, "1.8", "1.9")
        'Deprecated since v1.8 — no longer used. Will be removed in v1.9.'
        >>> _build_arg_deprecation_note("new_arg", "1.8", "1.9")
        'Deprecated since v1.8 — use `new_arg` instead. Will be removed in v1.9.'

    rR   )rS   reasonrT   )TEMPLATE_DOC_ARG_REASON_RENAMEDTEMPLATE_DOC_ARG_REASON_REMOVED!TEMPLATE_DOC_ARG_DEPRECATED_SINCETEMPLATE_DOC_ARG_DEPRECATEDTEMPLATE_DOC_ARG_REMOVE)rR   rS   rT   rV   templatenotes         r+   _build_arg_deprecation_noter^      sR    $ HO,	7/CCTsF4A0GbHHHD';	*BBBKr2   c                     t        j                  d      }t        |       D ]?  \  }}|j                  |      s|t	        |      t	        |j                               z
  fc S  y)uL  Return ``(section_start, section_indent)`` for a Google-style ``Args:`` header.

    Scans *lines* for an ``Args:`` or ``Arguments:`` header and returns its line
    index and leading indentation.  Returns ``(-1, 0)`` when not found.

    The match is intentionally strict: a line qualifies only when it consists
    of optional leading spaces followed by exactly ``Args:`` or ``Arguments:``
    with nothing else on the line (no trailing text).  This avoids accidental
    matches inside prose paragraphs.

    See `Google Python Style Guide — Functions and Methods
    <https://google.github.io/styleguide/pyguide.html#383-functions-and-methods>`_
    for the ``Args:`` section specification.

    Args:
        lines: Docstring already split into individual lines.

    Returns:
        A 2-tuple ``(section_start, section_indent)``.

    z^\s*(Args|Arguments):\s*$)r   )recompiler6   matchr.   lstrip)r3   _section_reir"   s       r+   _find_google_args_sectionrg      s]    , **9:KU# 54T"c$i#dkkm"44445 r2   section_startsection_indentc                    d}t        |dz   t        |             D ]I  }| |   j                         st        | |         t        | |   j                               z
  }||kD  r|} n |dk(  ry|dz   }t        |dz   t        |             D ]S  }| |   }|j                         st        |      t        |j                               z
  }||k  r ||fS ||kD  sN|} ||fS  ||fS )a  Return ``(arg_indent, continuation_indent)`` for a Google-style Args section.

    *arg_indent* is the column at which individual argument entries begin.
    *continuation_indent* is the column used for continuation lines within an
    argument entry (defaults to ``arg_indent + 4`` when not detectable).
    Returns ``(-1, -1)`` when the section has no non-empty child lines.

    Args:
        lines: Docstring already split into individual lines.
        section_start: Line index of the ``Args:`` / ``Arguments:`` header.
        section_indent: Leading indentation of that header line.

    Returns:
        A 2-tuple ``(arg_indent, continuation_indent)``.

    r`   r5   )r`   r`      ranger.   r-   rd   )r3   rh   ri   
arg_indentrf   current_indentcontinuation_indentr"   s           r+   _get_google_arg_indentsrq      s   " J=1$c%j1 8>> q]Sq1B-CCN.+
 R$q.=1$c%j1 	Qxzz|TS%77^+
 ***	 J&"0***	 ***r2   rn   arg_namec                 d   t        |dz   t        |             D ]  }| |   }|j                         st        |      t        |j                               z
  }||k  r y||k(  sK||d }t        |      t        |      kD  xr |t        |         dv }	||k(  s|j	                  |      s|	s|c S  y)a'  Return the line index of *arg_name* inside a Google-style Args section.

    Returns ``-1`` when *arg_name* is not found within the section.

    Args:
        lines: Docstring already split into individual lines.
        section_start: Line index of the ``Args:`` / ``Arguments:`` header.
        section_indent: Leading indentation of that header line.
        arg_indent: Leading indentation of argument entry lines.
        arg_name: Name of the argument to locate.

    Returns:
        Line index of the matching argument entry, or ``-1``.

    r5   Nz :(,r`   )rm   r.   r-   rd   
startswith)
r3   rh   ri   rn   rr   rf   r"   ro   resthas_arg_boundarys
             r+   _find_google_arg_linerw      s    $ =1$c%j1 Qxzz|TS%77^+  Z'
$D"4y3x=8ZT#h-=PTZ=ZxDOOH$=BR r2   	entry_idxentry_indentc                     |}t        |dz   t        |             D ]G  }| |   }|j                         s |S t        |      t        |j                               z
  |k  r |S |}I |S )a  Return the index of the last continuation line for a docstring entry.

    Scans forward from *entry_idx + 1* and stops at the first blank line or
    the first line whose indentation is ``<= entry_indent``.

    Note:
        A blank line within a multi-paragraph argument description is treated
        as the entry boundary.  Only the content up to that blank line receives
        the deprecation note; subsequent paragraphs are considered outside the
        entry.

    Args:
        lines: Docstring already split into individual lines.
        entry_idx: Line index of the entry's opening line.
        entry_indent: Leading indentation of that opening line.

    Returns:
        Index of the last line belonging to the entry (>= *entry_idx*).

    r5   rl   )r3   rx   ry   end_idxrf   r"   s         r+   _find_entry_endr|     sw    * G9q=#e*- Qxzz| N t9s4;;=))\9N  Nr2   r]   c                 ,   t        |       \  }}|dk(  r| dfS t        | ||      \  }}|dk(  r| dfS t        | ||||      }|dk(  r| dfS t        | ||      }t	        fd| ||dz    D              r| dfS d|z  z   }	| d|dz    |	gz   | |dz   d z   }
|
dfS )ut  Find *arg_name* in a Google-style ``Args:`` section and insert *note* below it.

    Supports both ``Args:`` and ``Arguments:`` section headers.  Returns the
    original list unchanged when no matching section or argument entry is found.

    Args:
        lines: Docstring already split into individual lines.
        arg_name: Name of the deprecated argument to locate.
        note: Text to insert as a continuation line under the matched entry.

    Returns:
        A 2-tuple ``(new_lines, found)`` where *found* is ``True`` when the
        argument was located and the note was successfully inserted.

    The note is inserted as a continuation line directly after the matched entry:

    .. code-block:: text

    Args:
            lr (float): Learning rate.
            old_cfg (object): Old config.
                Deprecated — use cfg instead.  # <-- inserted here

    r`   Fc              3   &   K   | ]  }|v  
 y wNr(   r)   lnr]   s     r+   r,   z-_annotate_google_style_arg.<locals>.<genexpr>]  s     
B"42:
B   r5   T N)rg   rq   rw   r|   any)r3   rr   r]   rh   ri   rn   rp   arg_line_idxr{   	note_line	new_liness     `        r+   _annotate_google_style_argr   6  s    2 %>e$D!M>e|&=e]Tb&c#J#Re|(~z[cdLre|e\:>G

BlWq[ A
BBd{))D0Im!$	{2U7Q;=5IIId?r2   c                    t        j                  dt        j                  |      z   dz         }d}d}t        |       D ]6  \  }}|j	                  |      }|s|}t        |j                  d            } n |dk(  r| dfS t        | ||      }	t        fd| ||	dz    D              r| dfS d	|d
z   z  z   }
| d|	dz    |
gz   | |	dz   d z   }|dfS )ue  Find ``:param arg_name:`` in a Sphinx-style docstring and insert *note* below it.

    Supports both ``:param arg_name:`` and ``:param SomeType arg_name:`` forms.
    Returns the original list unchanged when no matching ``:param`` field is found.

    Args:
        lines: Docstring already split into individual lines.
        arg_name: Name of the deprecated argument to locate.
        note: Text to insert as a continuation line under the matched field.

    Returns:
        A 2-tuple ``(new_lines, found)`` where *found* is ``True`` when the
        parameter was located and the note was successfully inserted.

    The note is inserted as a continuation line directly after the matched field::

        :param lr: Learning rate.
        :param old_cfg: Old config.
            Deprecated — use cfg instead.  # <-- inserted here
        :returns: Result.

    z^(\s*):param\s+(?:\S+\s+)?z\s*:r`   r   r5   Fc              3   &   K   | ]  }|v  
 y wr   r(   r   s     r+   r,   z-_annotate_sphinx_style_arg.<locals>.<genexpr>  s     
D"42:
Dr   Tr   rk   N)	ra   rb   escaper6   rc   r.   groupr|   r   )r3   rr   r]   patternparam_line_idxparam_indentrf   r"   mr{   r   r   s     `         r+   _annotate_sphinx_style_argr   d  s    . jj689LLwVWGNLU# 4MM$Nqwwqz?L e|e^\BG

Dnw{ C
DDd{|a'(4/Im!$	{2U7Q;=5IIId?r2   dep_infoc                 j   | j                   rd| j                    dnd}d}d}t        | j                        ra| j                  j                   d| j                  j                   }t        j                  | j                        rdnd}d| d| d}d	| d}t        | j                        }|d
k(  r	t        }|}nt        }|}g }	|D ]h  }
|
j                         j                  d      r|s%|
j                         j                  d      r|sG|	j                  |
| j                  ||dz         j |	S )a  Render the general deprecation notice lines for the given style.

    Selects the RST (``.. deprecated::``) or MkDocs (``!!! warning``) template
    based on ``dep_info.docstring_style``, substitutes ``deprecated_in``,
    ``remove_in``, and the target reference, and omits template lines whose
    placeholder resolves to an empty string.

    Args:
        dep_info: Frozen deprecation metadata attached to the decorated callable.

    Returns:
        A list of rendered notice lines (without leading body indentation).

    zWill be removed in rJ   r?   classfunczUse :z:`z
` instead.zUse `r   z%(remove_text)sz%(target_text)s)rS   remove_texttarget_text)rT   callabletarget
__module____name__inspectisclassrQ   rH   TEMPLATE_DOC_DEPRECATED_MKDOCSTEMPLATE_DOC_DEPRECATED_RSTr-   endswithappendrS   )r   r   target_text_rsttarget_text_mkdocsfull_target_nameref_typerH   r\   r   resultr"   s              r+   _build_general_notice_linesr     s?    BJASAS'(:(:';1=Y[KO &oo8898??;S;S:TU%oohoo>7F!(2.>-?zJ$%5$6jA/0H0HIO("1(.%F 
::<  !23K::<  !23KX%;%;Khstt	

 Mr2   
wrapped_fnc                    t        | d      r| j                  syt        |       sy| j                  j                         }| j                  }|j
                  rd}|j
                  j                         D ]M  \  }}t        ||j                  |j                        }t        |||      \  }}|st        |||      \  }}|rLd}O |rF|j                  t        j                  u r*t        j                   dj#                  |            | _        yt%        |      }dt&        t(           dt&        t(           dt*        fd	}	 |	||      ryt-        d
 |dd D        d      |j
                  r|r9|d   j/                         s&|j1                          |r|d   j/                         s&|j3                  d       |j5                  fd|D               t        j                   dj#                  |            | _        y|D 
cg c]  }
|
z   	 }}
t7        |      }|d| }||d }|r$|d   j/                         r|j3                  d       |j5                  |       |rr|r9|d   j/                         s&|j1                          |r|d   j/                         s&|r$|d   j/                         r|j3                  d       |j5                  |       t        j                   dj#                  |            | _        yc c}
w )u  Annotate a function's docstring with deprecation information.

    Two paths are taken depending on whether ``args_mapping`` is set:

    - **Inline arg path** (``args_mapping`` present): each deprecated argument is
      located in the ``Args:`` / ``Arguments:`` (Google style) or ``:param``
      (Sphinx style) section and a one-line deprecation note is inserted directly
      beneath it.  When ``target`` is ``True`` (self-deprecation) and all deprecated
      args are found, the function returns early and no general notice block is
      added.  When ``target`` is a callable or ``None``, the general block is
      always added after the inline annotations because the function itself is
      deprecated.
    - **General notice path** (no ``args_mapping``, or at least one arg was not
      found in the docstring): a deprecation notice is inserted before the first
      Google/NumPy section header (e.g. ``Args:``, ``Parameters``) when detected,
      otherwise appended at the end of the docstring.  The notice format depends
      on ``docstring_style``: Sphinx ``.. deprecated::`` directive (default
      ``"rst"``) or MkDocs/Markdown admonition (``"mkdocs"``/``"markdown"``).

    Args:
        wrapped_fn: Function whose docstring should be updated. Must have
            ``__deprecated__`` attribute set with deprecation metadata.

    Returns:
        None. Modifies the function's ``__doc__`` attribute in-place.

    Metadata Used:
        The function's ``__deprecated__`` attribute should be a
        :class:`~deprecate._types.DeprecationConfig` instance with:
        - deprecated_in: Version when deprecated
        - remove_in: Version when will be removed
        - target: Replacement callable (optional)
        - args_mapping: Mapping of old → new argument names (optional)

    Example:
        General notice path — no ``args_mapping``:

        >>> def new_func(): pass
        >>> def old_func():
        ...     '''Original docstring.'''
        ...     pass
        >>> old_func.__deprecated__ = DeprecationConfig(
        ...     deprecated_in='1.0',
        ...     remove_in='2.0',
        ...     target=new_func,
        ... )
        >>> _update_docstring_with_deprecation(old_func)
        >>> print(old_func.__doc__) # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
        Original docstring.
        <BLANKLINE>
        .. deprecated:: 1.0
           Will be removed in 2.0.
           Use :func:`...new_func` instead.

        Inline arg path — self-deprecation (``target=True``) with all args found:

        >>> def fn_with_args(x: int, old_arg: str = "") -> str:
        ...     '''Do something.
        ...
        ...     Args:
        ...         x: The main input.
        ...         old_arg: The old argument.
        ...     '''
        ...     return str(x)
        >>> fn_with_args.__deprecated__ = DeprecationConfig(
        ...     deprecated_in='1.0',
        ...     remove_in='2.0',
        ...     target=TargetMode.ARGS_REMAP,
        ...     args_mapping={'old_arg': None},
        ... )
        >>> _update_docstring_with_deprecation(fn_with_args)
        >>> 'Deprecated since v1.0' in fn_with_args.__doc__
        True
        >>> '.. deprecated::' in fn_with_args.__doc__
        False

    Note:
        Does nothing if the function has no docstring or no ``__deprecated__`` attribute.
        To preserve Google/NumPy parsing, the general notice is inserted before the
        first section header (e.g. ``Args:`` or ``Parameters``) when detected.

    __doc__NTF
	doc_linesblock_linesr#   c           	          syt               t              z
  }|dk  ryd   j                         }t        |dz         D ]C      j                         |k7  rt         fdt        t                    D              sC y y)zReturn True if ``block_lines`` appears as a contiguous block in ``doc_lines``.

        Lines are compared using ``.strip()`` to ignore leading/trailing whitespace.

        Fr   r5   c              3   r   K   | ].  }|z      j                         |   j                         k(   0 y wr   )r-   )r)   offsetr   r   starts     r+   r,   zU_update_docstring_with_deprecation.<locals>._has_deprecation_block.<locals>.<genexpr>8  s;      U[	%&.)//1[5H5N5N5PPs   47T)r.   r-   rm   r/   )r   r   	max_startfirstr   s   ``  @r+   _has_deprecation_blockzB_update_docstring_with_deprecation.<locals>._has_deprecation_block)  s     	NS%55	q=A$$&9q=) 	E%%'50 _dehiteu_v  	 r2   c              3      K   | ]=  }|j                         s|d t        |      t        |j                               z
    ? y wr   )r-   r.   rd   )r)   r"   s     r+   r,   z5_update_docstring_with_deprecation.<locals>.<genexpr>B  s4     VD.D	C..	/Vs
   A-Ar5   r?   r`   c              3   (   K   | ]	  }|z     y wr   r(   )r)   r   body_indents     r+   r,   z5_update_docstring_with_deprecation.<locals>.<genexpr>J  s     B"[2%Bs   r   )hasattrr   r   
splitlines__deprecated__args_mappingitemsr^   rS   rT   r   r   r   r   
ARGS_REMAPr   cleandocjoinr   listrL   boolnextr-   popr   extendr;   )r   r3   r   all_args_foundrr   rR   r]   founddeprecation_linesr   r   
insert_idxprefixsuffixr   s                 @r+   "_update_docstring_with_deprecationr     s   f :y)1C1C ,))+E((H!)!6!6!<!<!> 	'Hg.w8N8NPXPbPbcD5eXtLLE59%4Pu!&	' hoo1F1FF!(!1!1$))E2B!CJ3H=$s) $s) PT , e%67VE!"IV
K E"IOO-IIK E"IOO-RB0ABB$--dii.>?
 9JJ"[2-JJ3E:
{
#z{#fRj&&(MM"'(!1!1!3

 !1!1!3&)//+b!MM&!$--dii.?@
 Ks   <K4)-r   r   r@   ra   rC   typingr   r   r   deprecate._typesr   r   r   r   r   rY   rZ   r[   rX   rW   rO   	frozensetr   rL   __annotations__r8   r9   r   r1   r   intr;   rG   rQ   r^   tuplerg   rq   rw   r|   r   r   r   objectr   r(   r2   r+   <module>r      s\  2  	 	 
 * * Q Q "  %] != ? "2 "= #)%8Yab -67N-O IcN O  HS HT H$s)  GO4 0<s <w7O <$# s WZ _b 4T#Y 5c? :(+49 (+S (+RU (+Z_`ceh`hZi (+V9%(:=KNZ]B49  C C @+d3i +3 +c +eTXY\T]_cTcNd +\+d3i +3 +c +eTXY\T]_cTcNd +\)*; )S	 )X]A6 ]Ad ]Ar2   