a
    IDg?                     @   s   d Z ddlZddlZ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ZdZeeZdd	d
ZdddZdddZdd Zdd ZefddZG dd deZdS )a;  
Interactive terminal prompts.

The :mod:`~humanfriendly.prompts` module enables interaction with the user
(operator) by asking for confirmation (:func:`prompt_for_confirmation()`) and
asking to choose from a list of options (:func:`prompt_for_choice()`). It works
by rendering interactive prompts on the terminal.
    N)interactive_prompt)HIGHLIGHT_COLOR
ansi_strip	ansi_wrapconnected_to_terminalterminal_supports_colorswarning)formatconcatenate)	MAX_ATTEMPTSTooManyInvalidRepliesloggerprepare_friendly_promptsprepare_prompt_textprompt_for_choiceprompt_for_confirmationprompt_for_inputretry_limit
   Tc                 C   s  t | dd}|rdn|dur dnd}|dt |td 7 }td	t|  t D ]}t|d
|dd}| dv rtd|  dS | dv rtd|  dS |s|durtd|rdnd |  S |rd| nd}td|rdnd||t	 t
d|rdnd
|d qRdS )a  
    Prompt the user for confirmation.

    :param question: The text that explains what the user is confirming (a string).
    :param default: The default value (a boolean) or :data:`None`.
    :param padding: Refer to the documentation of :func:`prompt_for_input()`.
    :returns: - If the user enters 'yes' or 'y' then :data:`True` is returned.
              - If the user enters 'no' or 'n' then :data:`False`  is returned.
              - If the user doesn't enter any text or standard input is not
                connected to a terminal (which makes it impossible to prompt
                the user) the value of the keyword argument ``default`` is
                returned (if that value is not :data:`None`).
    :raises: - Any exceptions raised by :func:`retry_limit()`.
             - Any exceptions raised by :func:`prompt_for_input()`.

    When `default` is :data:`False` and the user doesn't enter any text an
    error message is printed and the prompt is repeated:

    >>> prompt_for_confirmation("Are you sure?")
     <BLANKLINE>
     Are you sure? [y/n]
     <BLANKLINE>
     Error: Please enter 'yes' or 'no' (there's no default choice).
     <BLANKLINE>
     Are you sure? [y/n]

    The same thing happens when the user enters text that isn't recognized:

    >>> prompt_for_confirmation("Are you sure?")
     <BLANKLINE>
     Are you sure? [y/n] about what?
     <BLANKLINE>
     Error: Please enter 'yes' or 'no' (the text 'about what?' is not recognized).
     <BLANKLINE>
     Are you sure? [y/n]
    Tboldz[Y/n]Nz[y/N]z[y/n]z %s )colorz5Requesting interactive confirmation from terminal: %r paddingstrip)yyesz#Confirmation granted by reply (%r).)nnoz"Confirmation denied by reply (%r).F,Default choice selected by empty reply (%r).ZgrantedZdeniedzthe text '%s' is not recognizedthere's no default choice&Got %s reply (%s), retrying (%i/%i) ..invalidemptyz6{indent}Error: Please enter 'yes' or 'no' ({details}). )indentdetails)r   r   r   debugr   rstripr   r   lowerr   r   )questiondefaultr   prompt_texthintattemptreplyr'    r1   f/mounts/lovelace/software/anaconda3/envs/paleomix/lib/python3.9/site-packages/humanfriendly/prompts.pyr   6   s8    &


r   c              	      s8  |rdnd}t | } t| dkr8td| d  | d S | sDtd|rLdndd fd	d
t| ddD dg}t|dd}tdtt	t
|  t D ]}t|d|dd}|sԈ durtd     S | r(t|d }d|  krt| k r(n ntd| | | | |   S g }| D ]Z}	| }
|	 }|
|krftd|	 |	    S |
|v r0t|
dkr0||	 q0t|dkrtd|d | |d   S |rtd|t|}n:| rtdt|}n |r| std|}nd}td|rdnd||t td|| qdS )a  
    Prompt the user to select a choice from a group of options.

    :param choices: A sequence of strings with available options.
    :param default: The default choice if the user simply presses Enter
                    (expected to be a string, defaults to :data:`None`).
    :param padding: Refer to the documentation of
                    :func:`~humanfriendly.prompts.prompt_for_input()`.
    :returns: The string corresponding to the user's choice.
    :raises: - :exc:`~exceptions.ValueError` if `choices` is an empty sequence.
             - Any exceptions raised by
               :func:`~humanfriendly.prompts.retry_limit()`.
             - Any exceptions raised by
               :func:`~humanfriendly.prompts.prompt_for_input()`.

    When no options are given an exception is raised:

    >>> prompt_for_choice([])
    Traceback (most recent call last):
      File "humanfriendly/prompts.py", line 148, in prompt_for_choice
        raise ValueError("Can't prompt for choice without any options!")
    ValueError: Can't prompt for choice without any options!

    If a single option is given the user isn't prompted:

    >>> prompt_for_choice(['only one choice'])
    'only one choice'

    Here's what the actual prompt looks like by default:

    >>> prompt_for_choice(['first option', 'second option'])
    <BLANKLINE>
      1. first option
      2. second option
    <BLANKLINE>
     Enter your choice as a number or unique substring (Control-C aborts): second
    <BLANKLINE>
    'second option'

    If you don't like the whitespace (empty lines and indentation):

    >>> prompt_for_choice(['first option', 'second option'], padding=False)
     1. first option
     2. second option
    Enter your choice as a number or unique substring (Control-C aborts): first
    'first option'
    r%   r      z=Skipping interactive prompt because there's only option (%r).r   z,Can't prompt for choice without any options!z


c                    s,   g | ]$\}}d ||f | kr"dnd qS )z %i. %sz (default choice)r   r1   ).0ichoicer,   r1   r2   
<listcomp>   s   z%prompt_for_choice.<locals>.<listcomp>)startzFEnter your choice as a number or unique substring (Control-C aborts): Tr   z=Requesting interactive choice on terminal (options are %s) ..r   Nr    z+Option (%r) selected by numeric reply (%s).z,Option (%r) selected by reply (exact match).z6Option (%r) selected by reply (substring match on %r).z*text '%s' matches more than one choice: %sznumber %i is not a valid choicez#text '%s' doesn't match any choicesr!   r"   r#   r$   z%sError: Invalid input (%s).)listlenr   r(   
ValueErrorjoin	enumerater   r
   mapreprr   r   isdigitintr*   appendr	   isspacer   r   )choicesr,   r   r&   r-   r/   r0   indexmatchesr7   Zlower_replyZlower_choicer'   r1   r8   r2   r   x   sf    0
	
 

r   c              
   C   s   t   d}zt|r$d|  } | dd} z0t| }W |du rDtjd |r|tjd n&|du rjtjd |rztjd 0 W nb ty } zJt|tr|durt	
d| |W  Y d}~S t	jddd  W Y d}~n
d}~0 0 |dur|s|S | S dS )a  
    Prompt the user for input (free form text).

    :param question: An explanation of what is expected from the user (a string).
    :param default: The return value if the user doesn't enter any text or
                    standard input is not connected to a terminal (which
                    makes it impossible to prompt the user).
    :param padding: Render empty lines before and after the prompt to make it
                    stand out from the surrounding text? (a boolean, defaults
                    to :data:`True`)
    :param strip: Strip leading/trailing whitespace from the user's reply?
    :returns: The text entered by the user (a string) or the value of the
              `default` argument.
    :raises: - :exc:`~exceptions.KeyboardInterrupt` when the program is
               interrupted_ while the prompt is active, for example
               because the user presses Control-C_.
             - :exc:`~exceptions.EOFError` when reading from `standard input`_
               fails, for example because the user presses Control-D_ or
               because the standard input stream is redirected (only if
               `default` is :data:`None`).

    .. _Control-C: https://en.wikipedia.org/wiki/Control-C#In_command-line_environments
    .. _Control-D: https://en.wikipedia.org/wiki/End-of-transmission_character#Meaning_in_Unix
    .. _interrupted: https://en.wikipedia.org/wiki/Unix_signal#SIGINT
    .. _standard input: https://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29
    Nr4   z
 z6Got EOF from terminal, returning default value (%r) ..z0Interactive prompt was interrupted by exception!T)exc_info)r   replacer   sysstderrwriteBaseException
isinstanceEOFErrorr   r(   r   r   )r+   r,   r   r   r0   er1   r1   r2   r      s2    
r   c                 K   s(   t tjr$t| fdttji|S | S )a  
    Wrap a text to be rendered as an interactive prompt in ANSI escape sequences.

    :param prompt_text: The text to render on the prompt (a string).
    :param options: Any keyword arguments are passed on to :func:`.ansi_wrap()`.
    :returns: The resulting prompt text (a string).

    ANSI escape sequences are only used when the standard output stream is
    connected to a terminal. When the standard input stream is connected to a
    terminal any escape sequences are wrapped in "readline hints".
    Zreadline_hints)r   rK   stdoutr   r   stdin)r-   optionsr1   r1   r2   r   8  s    r   c                  C   s$   zddl } W n ty   Y n0 dS )u  
    Make interactive prompts more user friendly.

    The prompts presented by :func:`python2:raw_input()` (in Python 2) and
    :func:`python3:input()` (in Python 3) are not very user friendly by
    default, for example the cursor keys (:kbd:`←`, :kbd:`↑`, :kbd:`→` and
    :kbd:`↓`) and the :kbd:`Home` and :kbd:`End` keys enter characters instead
    of performing the action you would expect them to. By simply importing the
    :mod:`readline` module these prompts become much friendlier (as mentioned
    in the Python standard library documentation).

    This function is called by the other functions in this module to enable
    user friendly prompts.
    r   N)readlineImportError)rU   r1   r1   r2   r   I  s    r   c                 c   s:   t | D ]}|d V  qd}||  }t| t|dS )a	  
    Allow the user to provide valid input up to `limit` times.

    :param limit: The maximum number of attempts (a number,
                  defaults to :data:`MAX_ATTEMPTS`).
    :returns: A generator of numbers starting from one.
    :raises: :exc:`TooManyInvalidReplies` when an interactive prompt
             receives repeated invalid input (:data:`MAX_ATTEMPTS`).

    This function returns a generator for interactive prompts that want to
    repeat on invalid input without getting stuck in infinite loops.
    r3   zTReceived too many invalid replies on interactive prompt, giving up! (tried %i times)N)ranger   r   r   )limitr6   msgZformatted_msgr1   r1   r2   r   _  s    
r   c                   @   s   e Zd ZdZdS )r   zLRaised by interactive prompts when they've received too many invalid inputs.N)__name__
__module____qualname____doc__r1   r1   r1   r2   r   v  s   r   )NT)NT)NTT)r]   loggingrK   Zhumanfriendly.compatr   Zhumanfriendly.terminalr   r   r   r   r   r   Zhumanfriendly.textr	   r
   __all__r   	getLoggerrZ   r   r   r   r   r   r   r   	Exceptionr   r1   r1   r1   r2   <module>	   s   
 

B
r
N