U
    des                  
   @   sJ  d 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	 ddl
mZ ddlmZmZmZmZmZmZmZmZmZmZmZ zddlmZ eegZW n ek
r   egZY nX ddlmZ dd	lmZm Z m!Z!m"Z"m#Z#m$Z$ dd
l%m&Z&m'Z' ddl(m)Z) ddl*m+Z+ ddddgZ,G dd deZ-d0eee- e.ee' dddZ/e'ee0ef dddZ1d1eee- ddddZ2e'e.ddddZ3ee' ee' e.ee' ddd Z4d2ee0 e0e.d"d#d$Z5d3eee ee- ee0 eee0ef  eee0ef  dd%d&dZ6eee0e7f d'd(d)Z8ee0ee dd*d+dZ9G d,d- d-e)Z:G d.d/ d/Z;dS )4z^
Assembling
~~~~~~~~~~

Functions and classes to properly assemble your commands in a parser.
    N)OPTIONALZERO_OR_MOREArgumentParser)OrderedDict)Enum)AnyCallableDictIteratorListLiteralOptionalTupleUnionget_args
get_origin)	UnionType)COMPLETION_ENABLED)ATTR_ALIASES	ATTR_ARGS	ATTR_NAMEDEFAULT_ARGUMENT_TEMPLATEDEST_FUNCTIONPARSER_FORMATTER)
NotDefinedParserAddArgumentSpec)AssemblingError)get_subparsersset_default_commandadd_commandsadd_subcommandsNameMappingPolicyc                   @   s   e Zd ZdZdZdZdS )r!   a:  
    Represents possible approaches to treat default values when inferring argument
    specification from function signature.

    * `BY_NAME_IF_KWONLY` is the default and recommended approach introduced
      in v0.30.  It enables fine control over two aspects:

      * positional vs named;
      * required vs optional.

      "Normal" arguments are identified by position, "kwonly" are identified by
      name, regardless of the presence of default values.  A positional with a
      default value becomes optional but still positional (``nargs=OPTIONAL``).
      A kwonly argument without a default value becomes a required named
      argument.

      Example::

          def func(alpha, beta=1, *, gamma, delta=2): ...

      is equivalent to::

          prog alpha [beta] --gamma [--delta DELTA]

      That is, ``alpha`` and ``--gamma`` are mandatory while ``beta`` and
      ``--delta`` are optional (they have default values).

    * `BY_NAME_IF_HAS_DEFAULT` is very close to the the legacy approach
      (pre-v0.30).  If a function argument has a default value, it becomes an
      "option" (called by name, like ``--foo``); otherwise it's treated as a
      positional argument.

      Example::

          def func(alpha, beta=1, *, gamma, delta=2): ...

      is equivalent to::

          prog [--beta BETA] [--delta DELTA] alpha gamma

      That is, ``alpha`` and ``gamma`` are mandatory and positional, while
      ``--beta`` and ``--delta`` are optional (they have default values).  Note
      that it's impossible to have an optional positional or a mandatory named
      argument.

      The difference between this policy and the behaviour of Argh before
      v0.30 is in the treatment of kwonly arguments without default values:
      they used to become ``--foo FOO`` (required) but for the sake of
      simplicity they are treated as positionals.  If you are already using
      kwonly args, please consider the better suited policy `BY_NAME_IF_KWONLY`
      instead.

    It is recommended to migrate any older code to `BY_NAME_IF_KWONLY`.

    .. versionadded:: 0.30
    z6specify CLI argument by name if it has a default valuez4specify CLI argument by name if it comes from kwonlyN)__name__
__module____qualname____doc__BY_NAME_IF_HAS_DEFAULTZBY_NAME_IF_KWONLY r'   r'   .lib/python3.8/site-packages/argh/assembling.pyr!   A   s   9F)functionname_mapping_policycan_use_hintsreturnc                 #   s  |r|t krtd| t| }tdd |j D }dd |j D }dd |D tfddtD t	fddD  t
tt tt f d	 fd
d}|j D ]}||j\}}	|j|jk	r|j}
nt}
i }|r| j}|j|krt||j }|j|j|jfkr|
tkrx|sxtd|j d| j d }|rdt|tt| t j}t |j||
|d}|
tkr|t jkr|	|_!nt"|_#|rd|j$kr|j$%d}|dkrt"|_#|t jkrt&|j't(r|j$)dt(kr|j$d= |V  q|j|j*krt |j||
|d}|t jkrV|
tkrl|	|_!n|	|_!|
tkrld|_+|rt&|j't(r|j$)dt(kr|j$d= |V  q|j|j,krt |j|j-ddgt.|dV  qd S )NzUnknown name mapping policy c                 s   s   | ]}|j |jkV  qd S N)kindKEYWORD_ONLY.0pr'   r'   r(   	<genexpr>   s    z/infer_argspecs_from_function.<locals>.<genexpr>c                 S   s*   g | ]"}|j |jk	s |j|jkr|jqS r'   )defaultemptyr.   r/   namer0   r'   r'   r(   
<listcomp>   s    z0infer_argspecs_from_function.<locals>.<listcomp>c                 S   s   g | ]}|d  qS )r   r'   )r1   ar'   r'   r(   r7      s     c                 3   s   | ]}|  |fV  qd S r-   )countr1   char)named_arg_charsr'   r(   r3      s    c                 3   s   | ]}d  | k r|V  qdS )   Nr'   r:   )named_arg_char_countsr'   r(   r3      s     r,   c                    sP   |  dd}|g}| d  k}|r<d|d  d| g}nd| g}||fS )N_-r   z--)replace)Zarg_nameZcliified_arg_namepositionalsZcan_have_short_optoptions)conflicting_optsr'   r(   _make_cli_arg_names_options   s    zAinfer_argspecs_from_function.<locals>._make_cli_arg_names_optionsz
                    Argument "z" in function "a  "
                    is not keyword-only but has a default value.

                    Please note that since Argh v.0.30 the default name mapping
                    policy has changed.

                    More information:
                    https://argh.readthedocs.io/en/latest/changes.html#version-0-30-0-2023-10-21

                    You need to upgrade your functions so that the arguments
                    that have default values become keyword-only:

                        f(x=1) -> f(*, x=1)

                    If you actually want an optional positional argument,
                    please set the name mapping policy explicitly to `BY_NAME_IF_KWONLY`.

                    If you choose to postpone the migration, you have two options:

                    a) set the policy explicitly to `BY_NAME_IF_HAS_DEFAULT`;
                    b) pin Argh version to 0.29 until you are ready to migrate.

                    Thank you for understanding!
                    )func_arg_namecli_arg_namesdefault_valueother_add_parser_kwargsrequiredFtypeTr@   rA   )rG   rH   nargsrJ   )/r!   NotImplementedErrorinspect	signatureany
parametersvaluesdictsettupler   r   strr6   r4   r5   r   __annotations__TypingHintArgSpecGuessertyping_hint_to_arg_spec_paramsr.   ZPOSITIONAL_ONLYZPOSITIONAL_OR_KEYWORDtextwrapdedentr"   stripArgumentNameMappingErrorwarningswarnDeprecationWarningr&   r   rH   r   rM   rJ   pop
isinstancerI   boolgetr/   Zis_requiredZVAR_POSITIONALrB   r   )r)   r*   r+   func_signatureZ
has_kwonlyZ
named_argsrF   Z	parameterZcli_arg_names_positionalZcli_arg_names_optionsrI   Zextra_spec_kwargsZhintsmessageZarg_specvaluer'   )rE   r>   r<   r(   infer_argspecs_from_function   s    
"#





ri   )parser_add_argument_specr,   c                 C   s   | j }i }| jd d }d}| j}|dtfkrt|tr`|s|ddkr|rVdnd|d< nJ|ddkrt|tt	frd	|krt
|d	< n|dd
|krt||d< |drdt|t| krt|d d |d< |S )u  
    Given an argument specification, returns types, actions, etc. that could be
    guessed from it:

    * ``default=3`` → ``type=int``

      TODO: deprecate in favour of ``foo: int = 3`` in func signature.

    * ``choices=[3]`` → ``type=int``

      TODO: deprecate in favour of ``foo: int`` in func signature.

    * ``type=bool`` → ``action="store_false"`` or ``action="store_true"``
      (if action was not explicitly defined).

    r   rA   )storeappendNactionstore_false
store_truerL   rM   rk   choices)rJ   rH   
startswithrI   r   rc   rd   re   listrV   r   rL   )rj   rJ   Zguessedis_positionalZTYPE_AWARE_ACTIONSrI   r'   r'   r(   +guess_extra_parser_add_argument_spec_kwargs6  s(    

rt   )r)   r*   r,   c                 C   s  t |}tdd |j D }t|tg }| }tt|||d}|rb|sb|sbt	|j
 d|sl|}nLzt|||d}W n8 t	k
r }	 zt	|j
 d|	 |	W 5 d}	~	X Y nX |D ]}
t|
| jd z| j|
j|
 }W nT tk
r8 }	 z4d	|
j}t|j
 d
|
j d| d|	 |	W 5 d}	~	X Y nX tr|
jr|
j|_qt |}|rl| jsl|| _| jf t|i dS )a  
    Sets default command (i.e. a function) for given parser.

    If `parser.description` is empty and the function has a docstring,
    it is used as the description.

    :param function:

        The function to use as the command.

    :name_mapping_policy:

        The policy to use when mapping function arguments onto CLI arguments.
        See :class:`.NameMappingPolicy`.  If not defined explicitly,
        :meth:`.NameMappingPolicy.BY_NAME_IF_KWONLY` is used.

        .. versionadded:: 0.30

        .. versionchanged:: 0.30.2
           Raises `ArgumentNameMappingError` if the policy was not explicitly
           defined and a non-kwonly argument has a default value.  The reason
           is that it's very likely to be a case of non-migrated code where
           the argument was intended to be mapped onto a CLI option.  It's
           better to fail explicitly than to silently change the CLI API.

    .. note::

       If there are both explicitly declared arguments (e.g. via
       :func:`~argh.decorators.arg`) and ones inferred from the function
       signature, declared ones will be merged into inferred ones.
       If an argument does not conform to the function signature,
       `ArgumentNameMappingError` is raised.

    .. note::

       If the parser was created with ``add_help=True`` (which is by default),
       option name ``-h`` is silently removed from any argument.

    c                 s   s   | ]}|j |jkV  qd S r-   )r.   ZVAR_KEYWORDr0   r'   r'   r(   r3     s     z&set_default_command.<locals>.<genexpr>)r*   r+   zW: cannot extend argument declarations for an endpoint function that takes no arguments.)inferred_argsdeclared_args	has_varkwz: Nspecparser_adds_help_arg/z: cannot add 'z' as )rO   rP   rQ   rR   rS   getattrr   rr   ri   r^   r"   !_merge_inferred_and_declared_args _extend_parser_add_argument_specadd_helpadd_argumentrH   Zget_all_kwargs	Exceptionjoinr   rG   r   Z	completerZgetdocdescriptionset_defaultsr   )parserr)   r*   rf   rw   rv   r+   ru   Zparser_add_argument_specsexcry   rm   Zerr_cli_argsZ	docstringr'   r'   r(   r   n  sh    ,


( 


 )ry   rz   r,   c                 C   sL   | j t|  d| j kr(| j jtd |rHd| jkrHdd | jD | _d S )Nhelpr   -hc                 S   s   g | ]}|d kr|qS )r   r'   )r1   r6   r'   r'   r(   r7     s      z4_extend_parser_add_argument_spec.<locals>.<listcomp>)rJ   updatert   r   rH   rx   r'   r'   r(   r~     s    
r~   )ru   rv   rw   r,   c              	      s   t   | D ]}| |j< q
|D ]}|}|j}| krt|j}t | j}||krddd}|| }	|| }
td| d|	 d|
 d | | q|r| |< q fdd	 D }d
|j}d
dd	 |D }td| d| qt  S )NZ
positionalZoptional)TFz
argument "z" declared as z (in function signature) and z (via decorator). If you've just migrated from Argh v.0.29, please check the new default NameMappingPolicy. Perhaps you need to replace `func(x=1)` with `func(*, x=1)`?c                 3   s   | ]} | j V  qd S r-   )rH   r1   xZspecs_by_func_arg_namer'   r(   r3   6  s   z4_merge_inferred_and_declared_args.<locals>.<genexpr>z, c                 s   s   | ]}d  |V  qdS )r{   N)r   r   r'   r'   r(   r3   ;  s     z	argument z" does not fit function signature: )	r   rG   _is_positionalrH   r^   r   r   rr   rS   )ru   rv   rw   rj   Zdeclared_specrG   Zdecl_positionalZinfr_positionalZkindsZkind_inferredZkind_declaredZdest_option_stringsZ	msg_flagsZmsg_signaturer'   r   r(   r}     sB    





r}   rA   )argsprefix_charsr,   c                 C   s2   | r| d st d| d d t|r.dS dS )Nr   zExpected at least one argumentFT)
ValueErrorrq   rV   )r   r   r'   r'   r(   r   E  s
    r   )r   	functionsr*   
group_namegroup_kwargsfunc_kwargsr,   c                 C   s   |pi }t | dd}|r:|j||dd}|jf |}n|rFtd|D ]:}t|\}	}
|rh|
| |j|	f|
}t|||d qJdS )a  
    Adds given functions as commands to given parser.

    :param parser:

        an :class:`argparse.ArgumentParser` instance.

    :param functions:

        a list of functions. A subparser is created for each of them.
        If the function is decorated with :func:`~argh.decorators.arg`, the
        arguments are passed to :meth:`argparse.ArgumentParser.add_argument`.
        See also :func:`~argh.dispatching.dispatch` for requirements
        concerning function signatures. The command name is inferred from the
        function name. Note that the underscores in the name are replaced with
        hyphens, i.e. function name "foo_bar" becomes command name "foo-bar".

    :param name_mapping_policy:

        See :class:`argh.assembling.NameMappingPolicy`.

        .. versionadded:: 0.30

    :param group_name:

        an optional string representing the group of commands. For example, if
        a command named "hello" is added without the group name, it will be
        available as "prog.py hello"; if the group name if specified as "greet",
        then the command will be accessible as "prog.py greet hello". The
        group itself is not callable, so "prog.py greet" will fail and only
        display a help message.

    :param func_kwargs:

        a `dict` of keyword arguments to be passed to each nested ArgumentParser
        instance created per command (i.e. per function).  Members of this
        dictionary have the highest priority, so a function's docstring is
        overridden by a `help` in `func_kwargs` (if present).

    :param group_kwargs:

        a `dict` of keyword arguments to be passed to the nested ArgumentParser
        instance under given `group_name`.

    .. note::

        This function modifies the parser object. Generally side effects are
        bad practice but we don't seem to have any choice as ArgumentParser is
        pretty opaque.
        You may prefer :meth:`~argh.helpers.ArghParser.add_commands` for a bit
        more predictable API.

    .. note::

       An attempt to add commands to a parser which already has a default
       function (e.g. added with :func:`~argh.assembling.set_default_command`)
       results in `AssemblingError`.

    T)Zcreatetitler   z2`group_kwargs` only makes sense with `group_name`.)r*   N)r   
add_parserre   add_subparsersr   _extract_command_meta_from_funcr   r   )r   r   r*   r   r   r   Zsubparsers_actionZsubsubparserfunccmd_namefunc_parser_kwargsZcommand_parserr'   r'   r(   r   M  s(    C 
  )r   r,   c                 C   s:   t | t| jdd}| jtd}t | tg |d< ||fS )Nr@   rA   )r   formatter_classaliases)r|   r   r"   rB   r%   r   r   )r   r   r   r'   r'   r(   r     s    r   )r   r   r   r,   c                 K   s   t | |||d dS )a  
    A wrapper for :func:`add_commands`.

    These examples are equivalent::

        add_commands(
            parser,
            [get, put],
            group_name="db",
            group_kwargs={
                "title": "database commands",
                "help": "CRUD for our silly database"
            }
        )

        add_subcommands(
            parser,
            "db",
            [get, put],
            title="database commands",
            help="CRUD for our database"
        )

    )r   r   N)r   )r   r   r   r   r'   r'   r(   r      s    c                   @   s   e Zd ZdS )r^   N)r"   r#   r$   r'   r'   r'   r(   r^     s   r^   c                   @   sN   e Zd ZeeeefZed	e	ee
eef dddZeee	 dddZdS )
rY   F)type_defrs   r,   c                    s  t | t|}|| jkr"d|iS |tkr2dtiS  tkrL|t|d dS t fddtD ri }|d }|| jkr||d< |tkrt|d< t |tkrt|d< | 	|}|r||d< td |krd|d< |S  tkri }t|d< |d | jkr|d |d< |S i S )	NrL   rM   r   )rp   rL   c                 3   s   | ]} |kV  qd S r-   r'   )r1   toriginr'   r(   r3     s     zJTypingHintArgSpecGuesser.typing_hint_to_arg_spec_params.<locals>.<genexpr>FrK   )
r   r   BASIC_TYPESrr   r   r   rL   rQ   UNION_TYPES!_extract_item_type_from_list_type)clsr   rs   r   ZretvalZfirst_subtypeZ	item_typer'   r   r(   rZ     s@    
 


z7TypingHintArgSpecGuesser.typing_hint_to_arg_spec_paramsr?   c                 C   s"   t |}|d | jkr|d S d S )Nr   )r   r   )r   r   r   r'   r'   r(   r     s    z:TypingHintArgSpecGuesser._extract_item_type_from_list_typeN)F)r"   r#   r$   rW   intfloatrd   r   classmethodrL   r	   r   rZ   r   r   r'   r'   r'   r(   rY     s     
3rY   )NF)N)rA   )NNNN)<r%   rO   r[   r_   argparser   r   r   collectionsr   enumr   typingr   r   r	   r
   r   r   r   r   r   r   r   typesr   r   ImportErrorZargh.completionr   Zargh.constantsr   r   r   r   r   r   Zargh.dtor   r   Zargh.exceptionsr   Z
argh.utilsr   __all__r!   rd   ri   rW   rt   r   r~   r}   r   r   rT   r   r    r^   rY   r'   r'   r'   r(   <module>
   s   4 @   9
; s Q    e  