Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -4,13 +4,16 @@ import collections.abc as cabc
|
|||
import inspect
|
||||
import io
|
||||
import itertools
|
||||
import re
|
||||
import sys
|
||||
import typing as t
|
||||
from contextlib import AbstractContextManager
|
||||
from contextlib import redirect_stdout
|
||||
from gettext import gettext as _
|
||||
|
||||
from ._compat import isatty
|
||||
from ._compat import strip_ansi
|
||||
from ._compat import WIN
|
||||
from .exceptions import Abort
|
||||
from .exceptions import UsageError
|
||||
from .globals import resolve_color_default
|
||||
|
|
@ -51,23 +54,66 @@ _ansi_colors = {
|
|||
_ansi_reset_all = "\033[0m"
|
||||
|
||||
|
||||
_HIDDEN_INPUT_MASK = "'***'"
|
||||
|
||||
|
||||
def _mask_hidden_input(message: str, value: str) -> str:
|
||||
"""Replace occurrences of ``value`` in ``message`` with a fixed mask.
|
||||
|
||||
Both ``repr(value)`` (the form built-in :class:`ParamType` errors use
|
||||
via ``{value!r}``) and the raw value are masked. The raw-value pass
|
||||
uses word-boundary lookarounds so a substring like ``"1"`` does not
|
||||
match inside ``"10"``, and ``"ent"`` does not match inside
|
||||
``"Authentication"``. The empty string is skipped to avoid matching
|
||||
at every boundary.
|
||||
"""
|
||||
message = message.replace(repr(value), _HIDDEN_INPUT_MASK)
|
||||
if value:
|
||||
message = re.sub(
|
||||
rf"(?<!\w){re.escape(value)}(?!\w)", _HIDDEN_INPUT_MASK, message
|
||||
)
|
||||
return message
|
||||
|
||||
|
||||
def hidden_prompt_func(prompt: str) -> str:
|
||||
import getpass
|
||||
|
||||
return getpass.getpass(prompt)
|
||||
|
||||
|
||||
def _readline_prompt(func: t.Callable[[str], str], text: str, err: bool) -> str:
|
||||
"""Call a prompt function, passing the full prompt on non-Windows so
|
||||
readline can handle line editing and cursor positioning correctly.
|
||||
|
||||
On Windows the prompt is written separately via :func:`echo` for
|
||||
colorama support, with only the last character passed to *func*.
|
||||
"""
|
||||
if WIN:
|
||||
# Write the prompt separately so that we get nice coloring
|
||||
# through colorama on Windows.
|
||||
echo(text[:-1], nl=False, err=err)
|
||||
# Echo the last character to stdout to work around an issue
|
||||
# where readline causes backspace to clear the whole line.
|
||||
return func(text[-1:])
|
||||
if err:
|
||||
with redirect_stdout(sys.stderr):
|
||||
return func(text)
|
||||
return func(text)
|
||||
|
||||
|
||||
def _build_prompt(
|
||||
text: str,
|
||||
suffix: str,
|
||||
show_default: bool = False,
|
||||
show_default: bool | str = False,
|
||||
default: t.Any | None = None,
|
||||
show_choices: bool = True,
|
||||
type: ParamType | None = None,
|
||||
type: ParamType[t.Any] | None = None,
|
||||
) -> str:
|
||||
prompt = text
|
||||
if type is not None and show_choices and isinstance(type, Choice):
|
||||
prompt += f" ({', '.join(map(str, type.choices))})"
|
||||
if isinstance(show_default, str):
|
||||
default = f"({show_default})"
|
||||
if default is not None and show_default:
|
||||
prompt = f"{prompt} [{_format_default(default)}]"
|
||||
return f"{prompt}{suffix}"
|
||||
|
|
@ -85,10 +131,10 @@ def prompt(
|
|||
default: t.Any | None = None,
|
||||
hide_input: bool = False,
|
||||
confirmation_prompt: bool | str = False,
|
||||
type: ParamType | t.Any | None = None,
|
||||
type: ParamType[t.Any] | t.Any | None = None,
|
||||
value_proc: t.Callable[[str], t.Any] | None = None,
|
||||
prompt_suffix: str = ": ",
|
||||
show_default: bool = True,
|
||||
show_default: bool | str = True,
|
||||
err: bool = False,
|
||||
show_choices: bool = True,
|
||||
) -> t.Any:
|
||||
|
|
@ -112,6 +158,8 @@ def prompt(
|
|||
convert a value.
|
||||
:param prompt_suffix: a suffix that should be added to the prompt.
|
||||
:param show_default: shows or hides the default value in the prompt.
|
||||
If this value is a string, it shows that string
|
||||
in parentheses instead of the actual value.
|
||||
:param err: if set to true the file defaults to ``stderr`` instead of
|
||||
``stdout``, the same as with echo.
|
||||
:param show_choices: Show or hide choices if the passed type is a Choice.
|
||||
|
|
@ -119,6 +167,10 @@ def prompt(
|
|||
show_choices is true and text is "Group by" then the
|
||||
prompt will be "Group by (day, week): ".
|
||||
|
||||
.. versionchanged:: 8.3.3
|
||||
``show_default`` can be a string to show a custom value instead
|
||||
of the actual default, matching the help text behavior.
|
||||
|
||||
.. versionchanged:: 8.3.1
|
||||
A space is no longer appended to the prompt.
|
||||
|
||||
|
|
@ -139,12 +191,7 @@ def prompt(
|
|||
def prompt_func(text: str) -> str:
|
||||
f = hidden_prompt_func if hide_input else visible_prompt_func
|
||||
try:
|
||||
# Write the prompt separately so that we get nice
|
||||
# coloring through colorama on Windows
|
||||
echo(text[:-1], nl=False, err=err)
|
||||
# Echo the last character to stdout to work around an issue where
|
||||
# readline causes backspace to clear the whole line.
|
||||
return f(text[-1:])
|
||||
return _readline_prompt(f, text, err)
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
# getpass doesn't print a newline if the user aborts input with ^C.
|
||||
# Allegedly this behavior is inherited from getpass(3).
|
||||
|
|
@ -177,10 +224,8 @@ def prompt(
|
|||
try:
|
||||
result = value_proc(value)
|
||||
except UsageError as e:
|
||||
if hide_input:
|
||||
echo(_("Error: The value you entered was invalid."), err=err)
|
||||
else:
|
||||
echo(_("Error: {e.message}").format(e=e), err=err)
|
||||
message = _mask_hidden_input(e.message, value) if hide_input else e.message
|
||||
echo(_("Error: {message}").format(message=message), err=err)
|
||||
continue
|
||||
if not confirmation_prompt:
|
||||
return result
|
||||
|
|
@ -235,12 +280,7 @@ def confirm(
|
|||
|
||||
while True:
|
||||
try:
|
||||
# Write the prompt separately so that we get nice
|
||||
# coloring through colorama on Windows
|
||||
echo(prompt[:-1], nl=False, err=err)
|
||||
# Echo the last character to stdout to work around an issue where
|
||||
# readline causes backspace to clear the whole line.
|
||||
value = visible_prompt_func(prompt[-1:]).lower().strip()
|
||||
value = _readline_prompt(visible_prompt_func, prompt, err).lower().strip()
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
raise Abort() from None
|
||||
if value in ("y", "yes"):
|
||||
|
|
@ -258,6 +298,25 @@ def confirm(
|
|||
return rv
|
||||
|
||||
|
||||
def get_pager_file(
|
||||
color: bool | None = None,
|
||||
) -> t.ContextManager[t.TextIO]:
|
||||
"""Context manager.
|
||||
|
||||
Yields a writable file-like object which can be used as an output pager.
|
||||
|
||||
.. versionadded:: 8.4.0
|
||||
|
||||
:param color: controls if the pager supports ANSI colors or not. The
|
||||
default is autodetection.
|
||||
"""
|
||||
from ._termui_impl import get_pager_file
|
||||
|
||||
color = resolve_color_default(color)
|
||||
|
||||
return get_pager_file(color=color)
|
||||
|
||||
|
||||
def echo_via_pager(
|
||||
text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str,
|
||||
color: bool | None = None,
|
||||
|
|
@ -273,7 +332,6 @@ def echo_via_pager(
|
|||
:param color: controls if the pager supports ANSI colors or not. The
|
||||
default is autodetection.
|
||||
"""
|
||||
color = resolve_color_default(color)
|
||||
|
||||
if inspect.isgeneratorfunction(text_or_generator):
|
||||
i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)()
|
||||
|
|
@ -285,9 +343,9 @@ def echo_via_pager(
|
|||
# convert every element of i to a text type if necessary
|
||||
text_generator = (el if isinstance(el, str) else str(el) for el in i)
|
||||
|
||||
from ._termui_impl import pager
|
||||
|
||||
return pager(itertools.chain(text_generator, "\n"), color)
|
||||
with get_pager_file(color=color) as pager:
|
||||
for text in itertools.chain(text_generator, "\n"):
|
||||
pager.write(text)
|
||||
|
||||
|
||||
@t.overload
|
||||
|
|
@ -614,13 +672,13 @@ def style(
|
|||
try:
|
||||
bits.append(f"\033[{_interpret_color(fg)}m")
|
||||
except KeyError:
|
||||
raise TypeError(f"Unknown color {fg!r}") from None
|
||||
raise TypeError(_("Unknown color {colour!r}").format(colour=fg)) from None
|
||||
|
||||
if bg:
|
||||
try:
|
||||
bits.append(f"\033[{_interpret_color(bg, 10)}m")
|
||||
except KeyError:
|
||||
raise TypeError(f"Unknown color {bg!r}") from None
|
||||
raise TypeError(_("Unknown color {colour!r}").format(colour=bg)) from None
|
||||
|
||||
if bold is not None:
|
||||
bits.append(f"\033[{1 if bold else 22}m")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue