123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784 |
- import inspect
- import io
- import itertools
- import sys
- import typing as t
- from gettext import gettext as _
- from ._compat import isatty
- from ._compat import strip_ansi
- from .exceptions import Abort
- from .exceptions import UsageError
- from .globals import resolve_color_default
- from .types import Choice
- from .types import convert_type
- from .types import ParamType
- from .utils import echo
- from .utils import LazyFile
- if t.TYPE_CHECKING:
- from ._termui_impl import ProgressBar
- V = t.TypeVar("V")
- # The prompt functions to use. The doc tools currently override these
- # functions to customize how they work.
- visible_prompt_func: t.Callable[[str], str] = input
- _ansi_colors = {
- "black": 30,
- "red": 31,
- "green": 32,
- "yellow": 33,
- "blue": 34,
- "magenta": 35,
- "cyan": 36,
- "white": 37,
- "reset": 39,
- "bright_black": 90,
- "bright_red": 91,
- "bright_green": 92,
- "bright_yellow": 93,
- "bright_blue": 94,
- "bright_magenta": 95,
- "bright_cyan": 96,
- "bright_white": 97,
- }
- _ansi_reset_all = "\033[0m"
- def hidden_prompt_func(prompt: str) -> str:
- import getpass
- return getpass.getpass(prompt)
- def _build_prompt(
- text: str,
- suffix: str,
- show_default: bool = False,
- default: t.Optional[t.Any] = None,
- show_choices: bool = True,
- type: t.Optional[ParamType] = None,
- ) -> str:
- prompt = text
- if type is not None and show_choices and isinstance(type, Choice):
- prompt += f" ({', '.join(map(str, type.choices))})"
- if default is not None and show_default:
- prompt = f"{prompt} [{_format_default(default)}]"
- return f"{prompt}{suffix}"
- def _format_default(default: t.Any) -> t.Any:
- if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"):
- return default.name
- return default
- def prompt(
- text: str,
- default: t.Optional[t.Any] = None,
- hide_input: bool = False,
- confirmation_prompt: t.Union[bool, str] = False,
- type: t.Optional[t.Union[ParamType, t.Any]] = None,
- value_proc: t.Optional[t.Callable[[str], t.Any]] = None,
- prompt_suffix: str = ": ",
- show_default: bool = True,
- err: bool = False,
- show_choices: bool = True,
- ) -> t.Any:
- """Prompts a user for input. This is a convenience function that can
- be used to prompt a user for input later.
- If the user aborts the input by sending an interrupt signal, this
- function will catch it and raise a :exc:`Abort` exception.
- :param text: the text to show for the prompt.
- :param default: the default value to use if no input happens. If this
- is not given it will prompt until it's aborted.
- :param hide_input: if this is set to true then the input value will
- be hidden.
- :param confirmation_prompt: Prompt a second time to confirm the
- value. Can be set to a string instead of ``True`` to customize
- the message.
- :param type: the type to use to check the value against.
- :param value_proc: if this parameter is provided it's a function that
- is invoked instead of the type conversion to
- 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.
- :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.
- For example if type is a Choice of either day or week,
- show_choices is true and text is "Group by" then the
- prompt will be "Group by (day, week): ".
- .. versionadded:: 8.0
- ``confirmation_prompt`` can be a custom string.
- .. versionadded:: 7.0
- Added the ``show_choices`` parameter.
- .. versionadded:: 6.0
- Added unicode support for cmd.exe on Windows.
- .. versionadded:: 4.0
- Added the `err` parameter.
- """
- 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.rstrip(" "), nl=False, err=err)
- # Echo a space to stdout to work around an issue where
- # readline causes backspace to clear the whole line.
- return f(" ")
- except (KeyboardInterrupt, EOFError):
- # getpass doesn't print a newline if the user aborts input with ^C.
- # Allegedly this behavior is inherited from getpass(3).
- # A doc bug has been filed at https://bugs.python.org/issue24711
- if hide_input:
- echo(None, err=err)
- raise Abort() from None
- if value_proc is None:
- value_proc = convert_type(type, default)
- prompt = _build_prompt(
- text, prompt_suffix, show_default, default, show_choices, type
- )
- if confirmation_prompt:
- if confirmation_prompt is True:
- confirmation_prompt = _("Repeat for confirmation")
- confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix)
- while True:
- while True:
- value = prompt_func(prompt)
- if value:
- break
- elif default is not None:
- value = default
- break
- 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) # noqa: B306
- continue
- if not confirmation_prompt:
- return result
- while True:
- value2 = prompt_func(confirmation_prompt)
- is_empty = not value and not value2
- if value2 or is_empty:
- break
- if value == value2:
- return result
- echo(_("Error: The two entered values do not match."), err=err)
- def confirm(
- text: str,
- default: t.Optional[bool] = False,
- abort: bool = False,
- prompt_suffix: str = ": ",
- show_default: bool = True,
- err: bool = False,
- ) -> bool:
- """Prompts for confirmation (yes/no question).
- If the user aborts the input by sending a interrupt signal this
- function will catch it and raise a :exc:`Abort` exception.
- :param text: the question to ask.
- :param default: The default value to use when no input is given. If
- ``None``, repeat until input is given.
- :param abort: if this is set to `True` a negative answer aborts the
- exception by raising :exc:`Abort`.
- :param prompt_suffix: a suffix that should be added to the prompt.
- :param show_default: shows or hides the default value in the prompt.
- :param err: if set to true the file defaults to ``stderr`` instead of
- ``stdout``, the same as with echo.
- .. versionchanged:: 8.0
- Repeat until input is given if ``default`` is ``None``.
- .. versionadded:: 4.0
- Added the ``err`` parameter.
- """
- prompt = _build_prompt(
- text,
- prompt_suffix,
- show_default,
- "y/n" if default is None else ("Y/n" if default else "y/N"),
- )
- while True:
- try:
- # Write the prompt separately so that we get nice
- # coloring through colorama on Windows
- echo(prompt.rstrip(" "), nl=False, err=err)
- # Echo a space to stdout to work around an issue where
- # readline causes backspace to clear the whole line.
- value = visible_prompt_func(" ").lower().strip()
- except (KeyboardInterrupt, EOFError):
- raise Abort() from None
- if value in ("y", "yes"):
- rv = True
- elif value in ("n", "no"):
- rv = False
- elif default is not None and value == "":
- rv = default
- else:
- echo(_("Error: invalid input"), err=err)
- continue
- break
- if abort and not rv:
- raise Abort()
- return rv
- def echo_via_pager(
- text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str],
- color: t.Optional[bool] = None,
- ) -> None:
- """This function takes a text and shows it via an environment specific
- pager on stdout.
- .. versionchanged:: 3.0
- Added the `color` flag.
- :param text_or_generator: the text to page, or alternatively, a
- generator emitting the text to page.
- :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[[], t.Iterable[str]], text_or_generator)()
- elif isinstance(text_or_generator, str):
- i = [text_or_generator]
- else:
- i = iter(t.cast(t.Iterable[str], text_or_generator))
- # 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)
- def progressbar(
- iterable: t.Optional[t.Iterable[V]] = None,
- length: t.Optional[int] = None,
- label: t.Optional[str] = None,
- show_eta: bool = True,
- show_percent: t.Optional[bool] = None,
- show_pos: bool = False,
- item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None,
- fill_char: str = "#",
- empty_char: str = "-",
- bar_template: str = "%(label)s [%(bar)s] %(info)s",
- info_sep: str = " ",
- width: int = 36,
- file: t.Optional[t.TextIO] = None,
- color: t.Optional[bool] = None,
- update_min_steps: int = 1,
- ) -> "ProgressBar[V]":
- """This function creates an iterable context manager that can be used
- to iterate over something while showing a progress bar. It will
- either iterate over the `iterable` or `length` items (that are counted
- up). While iteration happens, this function will print a rendered
- progress bar to the given `file` (defaults to stdout) and will attempt
- to calculate remaining time and more. By default, this progress bar
- will not be rendered if the file is not a terminal.
- The context manager creates the progress bar. When the context
- manager is entered the progress bar is already created. With every
- iteration over the progress bar, the iterable passed to the bar is
- advanced and the bar is updated. When the context manager exits,
- a newline is printed and the progress bar is finalized on screen.
- Note: The progress bar is currently designed for use cases where the
- total progress can be expected to take at least several seconds.
- Because of this, the ProgressBar class object won't display
- progress that is considered too fast, and progress where the time
- between steps is less than a second.
- No printing must happen or the progress bar will be unintentionally
- destroyed.
- Example usage::
- with progressbar(items) as bar:
- for item in bar:
- do_something_with(item)
- Alternatively, if no iterable is specified, one can manually update the
- progress bar through the `update()` method instead of directly
- iterating over the progress bar. The update method accepts the number
- of steps to increment the bar with::
- with progressbar(length=chunks.total_bytes) as bar:
- for chunk in chunks:
- process_chunk(chunk)
- bar.update(chunks.bytes)
- The ``update()`` method also takes an optional value specifying the
- ``current_item`` at the new position. This is useful when used
- together with ``item_show_func`` to customize the output for each
- manual step::
- with click.progressbar(
- length=total_size,
- label='Unzipping archive',
- item_show_func=lambda a: a.filename
- ) as bar:
- for archive in zip_file:
- archive.extract()
- bar.update(archive.size, archive)
- :param iterable: an iterable to iterate over. If not provided the length
- is required.
- :param length: the number of items to iterate over. By default the
- progressbar will attempt to ask the iterator about its
- length, which might or might not work. If an iterable is
- also provided this parameter can be used to override the
- length. If an iterable is not provided the progress bar
- will iterate over a range of that length.
- :param label: the label to show next to the progress bar.
- :param show_eta: enables or disables the estimated time display. This is
- automatically disabled if the length cannot be
- determined.
- :param show_percent: enables or disables the percentage display. The
- default is `True` if the iterable has a length or
- `False` if not.
- :param show_pos: enables or disables the absolute position display. The
- default is `False`.
- :param item_show_func: A function called with the current item which
- can return a string to show next to the progress bar. If the
- function returns ``None`` nothing is shown. The current item can
- be ``None``, such as when entering and exiting the bar.
- :param fill_char: the character to use to show the filled part of the
- progress bar.
- :param empty_char: the character to use to show the non-filled part of
- the progress bar.
- :param bar_template: the format string to use as template for the bar.
- The parameters in it are ``label`` for the label,
- ``bar`` for the progress bar and ``info`` for the
- info section.
- :param info_sep: the separator between multiple info items (eta etc.)
- :param width: the width of the progress bar in characters, 0 means full
- terminal width
- :param file: The file to write to. If this is not a terminal then
- only the label is printed.
- :param color: controls if the terminal supports ANSI colors or not. The
- default is autodetection. This is only needed if ANSI
- codes are included anywhere in the progress bar output
- which is not the case by default.
- :param update_min_steps: Render only when this many updates have
- completed. This allows tuning for very fast iterators.
- .. versionchanged:: 8.0
- Output is shown even if execution time is less than 0.5 seconds.
- .. versionchanged:: 8.0
- ``item_show_func`` shows the current item, not the previous one.
- .. versionchanged:: 8.0
- Labels are echoed if the output is not a TTY. Reverts a change
- in 7.0 that removed all output.
- .. versionadded:: 8.0
- Added the ``update_min_steps`` parameter.
- .. versionchanged:: 4.0
- Added the ``color`` parameter. Added the ``update`` method to
- the object.
- .. versionadded:: 2.0
- """
- from ._termui_impl import ProgressBar
- color = resolve_color_default(color)
- return ProgressBar(
- iterable=iterable,
- length=length,
- show_eta=show_eta,
- show_percent=show_percent,
- show_pos=show_pos,
- item_show_func=item_show_func,
- fill_char=fill_char,
- empty_char=empty_char,
- bar_template=bar_template,
- info_sep=info_sep,
- file=file,
- label=label,
- width=width,
- color=color,
- update_min_steps=update_min_steps,
- )
- def clear() -> None:
- """Clears the terminal screen. This will have the effect of clearing
- the whole visible space of the terminal and moving the cursor to the
- top left. This does not do anything if not connected to a terminal.
- .. versionadded:: 2.0
- """
- if not isatty(sys.stdout):
- return
- # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor
- echo("\033[2J\033[1;1H", nl=False)
- def _interpret_color(
- color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0
- ) -> str:
- if isinstance(color, int):
- return f"{38 + offset};5;{color:d}"
- if isinstance(color, (tuple, list)):
- r, g, b = color
- return f"{38 + offset};2;{r:d};{g:d};{b:d}"
- return str(_ansi_colors[color] + offset)
- def style(
- text: t.Any,
- fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None,
- bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None,
- bold: t.Optional[bool] = None,
- dim: t.Optional[bool] = None,
- underline: t.Optional[bool] = None,
- overline: t.Optional[bool] = None,
- italic: t.Optional[bool] = None,
- blink: t.Optional[bool] = None,
- reverse: t.Optional[bool] = None,
- strikethrough: t.Optional[bool] = None,
- reset: bool = True,
- ) -> str:
- """Styles a text with ANSI styles and returns the new string. By
- default the styling is self contained which means that at the end
- of the string a reset code is issued. This can be prevented by
- passing ``reset=False``.
- Examples::
- click.echo(click.style('Hello World!', fg='green'))
- click.echo(click.style('ATTENTION!', blink=True))
- click.echo(click.style('Some things', reverse=True, fg='cyan'))
- click.echo(click.style('More colors', fg=(255, 12, 128), bg=117))
- Supported color names:
- * ``black`` (might be a gray)
- * ``red``
- * ``green``
- * ``yellow`` (might be an orange)
- * ``blue``
- * ``magenta``
- * ``cyan``
- * ``white`` (might be light gray)
- * ``bright_black``
- * ``bright_red``
- * ``bright_green``
- * ``bright_yellow``
- * ``bright_blue``
- * ``bright_magenta``
- * ``bright_cyan``
- * ``bright_white``
- * ``reset`` (reset the color code only)
- If the terminal supports it, color may also be specified as:
- - An integer in the interval [0, 255]. The terminal must support
- 8-bit/256-color mode.
- - An RGB tuple of three integers in [0, 255]. The terminal must
- support 24-bit/true-color mode.
- See https://en.wikipedia.org/wiki/ANSI_color and
- https://gist.github.com/XVilka/8346728 for more information.
- :param text: the string to style with ansi codes.
- :param fg: if provided this will become the foreground color.
- :param bg: if provided this will become the background color.
- :param bold: if provided this will enable or disable bold mode.
- :param dim: if provided this will enable or disable dim mode. This is
- badly supported.
- :param underline: if provided this will enable or disable underline.
- :param overline: if provided this will enable or disable overline.
- :param italic: if provided this will enable or disable italic.
- :param blink: if provided this will enable or disable blinking.
- :param reverse: if provided this will enable or disable inverse
- rendering (foreground becomes background and the
- other way round).
- :param strikethrough: if provided this will enable or disable
- striking through text.
- :param reset: by default a reset-all code is added at the end of the
- string which means that styles do not carry over. This
- can be disabled to compose styles.
- .. versionchanged:: 8.0
- A non-string ``message`` is converted to a string.
- .. versionchanged:: 8.0
- Added support for 256 and RGB color codes.
- .. versionchanged:: 8.0
- Added the ``strikethrough``, ``italic``, and ``overline``
- parameters.
- .. versionchanged:: 7.0
- Added support for bright colors.
- .. versionadded:: 2.0
- """
- if not isinstance(text, str):
- text = str(text)
- bits = []
- if fg:
- try:
- bits.append(f"\033[{_interpret_color(fg)}m")
- except KeyError:
- raise TypeError(f"Unknown color {fg!r}") 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
- if bold is not None:
- bits.append(f"\033[{1 if bold else 22}m")
- if dim is not None:
- bits.append(f"\033[{2 if dim else 22}m")
- if underline is not None:
- bits.append(f"\033[{4 if underline else 24}m")
- if overline is not None:
- bits.append(f"\033[{53 if overline else 55}m")
- if italic is not None:
- bits.append(f"\033[{3 if italic else 23}m")
- if blink is not None:
- bits.append(f"\033[{5 if blink else 25}m")
- if reverse is not None:
- bits.append(f"\033[{7 if reverse else 27}m")
- if strikethrough is not None:
- bits.append(f"\033[{9 if strikethrough else 29}m")
- bits.append(text)
- if reset:
- bits.append(_ansi_reset_all)
- return "".join(bits)
- def unstyle(text: str) -> str:
- """Removes ANSI styling information from a string. Usually it's not
- necessary to use this function as Click's echo function will
- automatically remove styling if necessary.
- .. versionadded:: 2.0
- :param text: the text to remove style information from.
- """
- return strip_ansi(text)
- def secho(
- message: t.Optional[t.Any] = None,
- file: t.Optional[t.IO[t.AnyStr]] = None,
- nl: bool = True,
- err: bool = False,
- color: t.Optional[bool] = None,
- **styles: t.Any,
- ) -> None:
- """This function combines :func:`echo` and :func:`style` into one
- call. As such the following two calls are the same::
- click.secho('Hello World!', fg='green')
- click.echo(click.style('Hello World!', fg='green'))
- All keyword arguments are forwarded to the underlying functions
- depending on which one they go with.
- Non-string types will be converted to :class:`str`. However,
- :class:`bytes` are passed directly to :meth:`echo` without applying
- style. If you want to style bytes that represent text, call
- :meth:`bytes.decode` first.
- .. versionchanged:: 8.0
- A non-string ``message`` is converted to a string. Bytes are
- passed through without style applied.
- .. versionadded:: 2.0
- """
- if message is not None and not isinstance(message, (bytes, bytearray)):
- message = style(message, **styles)
- return echo(message, file=file, nl=nl, err=err, color=color)
- def edit(
- text: t.Optional[t.AnyStr] = None,
- editor: t.Optional[str] = None,
- env: t.Optional[t.Mapping[str, str]] = None,
- require_save: bool = True,
- extension: str = ".txt",
- filename: t.Optional[str] = None,
- ) -> t.Optional[t.AnyStr]:
- r"""Edits the given text in the defined editor. If an editor is given
- (should be the full path to the executable but the regular operating
- system search path is used for finding the executable) it overrides
- the detected editor. Optionally, some environment variables can be
- used. If the editor is closed without changes, `None` is returned. In
- case a file is edited directly the return value is always `None` and
- `require_save` and `extension` are ignored.
- If the editor cannot be opened a :exc:`UsageError` is raised.
- Note for Windows: to simplify cross-platform usage, the newlines are
- automatically converted from POSIX to Windows and vice versa. As such,
- the message here will have ``\n`` as newline markers.
- :param text: the text to edit.
- :param editor: optionally the editor to use. Defaults to automatic
- detection.
- :param env: environment variables to forward to the editor.
- :param require_save: if this is true, then not saving in the editor
- will make the return value become `None`.
- :param extension: the extension to tell the editor about. This defaults
- to `.txt` but changing this might change syntax
- highlighting.
- :param filename: if provided it will edit this file instead of the
- provided text contents. It will not use a temporary
- file as an indirection in that case.
- """
- from ._termui_impl import Editor
- ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension)
- if filename is None:
- return ed.edit(text)
- ed.edit_file(filename)
- return None
- def launch(url: str, wait: bool = False, locate: bool = False) -> int:
- """This function launches the given URL (or filename) in the default
- viewer application for this file type. If this is an executable, it
- might launch the executable in a new session. The return value is
- the exit code of the launched application. Usually, ``0`` indicates
- success.
- Examples::
- click.launch('https://click.palletsprojects.com/')
- click.launch('/my/downloaded/file', locate=True)
- .. versionadded:: 2.0
- :param url: URL or filename of the thing to launch.
- :param wait: Wait for the program to exit before returning. This
- only works if the launched program blocks. In particular,
- ``xdg-open`` on Linux does not block.
- :param locate: if this is set to `True` then instead of launching the
- application associated with the URL it will attempt to
- launch a file manager with the file located. This
- might have weird effects if the URL does not point to
- the filesystem.
- """
- from ._termui_impl import open_url
- return open_url(url, wait=wait, locate=locate)
- # If this is provided, getchar() calls into this instead. This is used
- # for unittesting purposes.
- _getchar: t.Optional[t.Callable[[bool], str]] = None
- def getchar(echo: bool = False) -> str:
- """Fetches a single character from the terminal and returns it. This
- will always return a unicode character and under certain rare
- circumstances this might return more than one character. The
- situations which more than one character is returned is when for
- whatever reason multiple characters end up in the terminal buffer or
- standard input was not actually a terminal.
- Note that this will always read from the terminal, even if something
- is piped into the standard input.
- Note for Windows: in rare cases when typing non-ASCII characters, this
- function might wait for a second character and then return both at once.
- This is because certain Unicode characters look like special-key markers.
- .. versionadded:: 2.0
- :param echo: if set to `True`, the character read will also show up on
- the terminal. The default is to not show it.
- """
- global _getchar
- if _getchar is None:
- from ._termui_impl import getchar as f
- _getchar = f
- return _getchar(echo)
- def raw_terminal() -> t.ContextManager[int]:
- from ._termui_impl import raw_terminal as f
- return f()
- def pause(info: t.Optional[str] = None, err: bool = False) -> None:
- """This command stops execution and waits for the user to press any
- key to continue. This is similar to the Windows batch "pause"
- command. If the program is not run through a terminal, this command
- will instead do nothing.
- .. versionadded:: 2.0
- .. versionadded:: 4.0
- Added the `err` parameter.
- :param info: The message to print before pausing. Defaults to
- ``"Press any key to continue..."``.
- :param err: if set to message goes to ``stderr`` instead of
- ``stdout``, the same as with echo.
- """
- if not isatty(sys.stdin) or not isatty(sys.stdout):
- return
- if info is None:
- info = _("Press any key to continue...")
- try:
- if info:
- echo(info, nl=False, err=err)
- try:
- getchar()
- except (KeyboardInterrupt, EOFError):
- pass
- finally:
- if info:
- echo(err=err)
|