Exemplo n.º 1
0
def should_do_markup(stream: TextIO = sys.stdout) -> bool:
    """Decide about use of ANSI colors."""
    py_colors = None

    # https://xkcd.com/927/
    for env_var in [
            "PY_COLORS", "CLICOLOR", "FORCE_COLOR", "ANSIBLE_FORCE_COLOR"
    ]:
        value = os.environ.get(env_var, None)
        if value is not None:
            py_colors = to_bool(value)
            break

    # If deliverately disabled colors
    if os.environ.get("NO_COLOR", None):
        return False

    # User configuration requested colors
    if py_colors is not None:
        return to_bool(py_colors)

    term = os.environ.get("TERM", "")
    if "xterm" in term:
        return True

    if term == "dumb":
        return False

    # Use tty detection logic as last resort because there are numerous
    # factors that can make isatty return a misleading value, including:
    # - stdin.isatty() is the only one returning true, even on a real terminal
    # - stderr returting false if user user uses a error stream coloring solution
    return stream.isatty()
Exemplo n.º 2
0
def run_tests(stdout: TextIO, stderr: TextIO, runner: Runner,
              executor: List[str], get_columns: Callable[[], int],
              tests: List[Tuple[str, str]]) -> int:
    status_format = '[{run_drivers}/{num_drivers}] {test}'

    num_drivers = len(tests)  # all test drivers
    run_drivers = 0  # drivers run so far

    with multiprocessing.Pool() as pool:
        args = [(runner, executor, t[0], t[1]) for t in tests]
        jobs = pool.imap_unordered(run_one, args)
        errors = {}

        for test, test_errors in jobs:
            run_drivers += 1
            if test_errors:
                errors[test] = test_errors

            columns = get_columns()
            message = trim(status_format.format(**locals()), columns)
            if stderr.isatty():
                print('\r' + ' ' * columns + '\r', end='', file=stderr)
                print(message, end='', file=stderr, flush=True)
            else:
                print(message, file=stderr, flush=True)
    print(file=stderr, flush=True)

    for test, test_errors in errors.items():
        for error in test_errors:
            print(f'FAIL TEST {test} CASE {error}', file=stdout)
    return 1 if errors else 0
Exemplo n.º 3
0
    def from_pty(cls, stdout: TextIO, term: Optional[str] = None) -> 'Vt100_Output':
        """
        Create an Output class from a pseudo terminal.
        (This will take the dimensions by reading the pseudo
        terminal attributes.)
        """
        # Normally, this requires a real TTY device, but people instantiate
        # this class often during unit tests as well. For convenience, we print
        # an error message, use standard dimensions, and go on.
        isatty = stdout.isatty()
        fd = stdout.fileno()

        if not isatty and fd not in cls._fds_not_a_terminal:
            msg = 'Warning: Output is not to a terminal (fd=%r).\n'
            sys.stderr.write(msg % fd)
            cls._fds_not_a_terminal.add(fd)

        def get_size() -> Size:
            # If terminal (incorrectly) reports its size as 0, pick a
            # reasonable default.  See
            # https://github.com/ipython/ipython/issues/10071
            rows, columns = (None, None)

            if isatty:
                rows, columns = _get_size(stdout.fileno())
            return Size(rows=rows or 24, columns=columns or 80)

        return cls(stdout, get_size, term=term)
Exemplo n.º 4
0
def render_link(
    text: str,
    href: Optional[str],
    print_alternative: bool = True,
    width: Optional[int] = None,
    pipe: TextIO = sys.stdout,
) -> str:
    """
    Prints a clickable hyperlink output if in a tty; otherwise just prints a text link

    :param text: The link anchor text
    :param href: The href, if exists
    :param print_alternative: If true, only emits link if OSC8 links are supported, otherwise prints href after text
    :param width: Minimum link width
    :param pipe: The text IO via which this link will be emitted
    :return: The rendered link
    """
    is_rendered = False
    if href:  # Don't render if href is None or empty
        if pipe.isatty() and DO_PRINT_LINKS:
            text = f"{OSC_8}{href}{BEL}{text}{OSC_8}{BEL}"
            is_rendered = True
            if width:
                width += LINK_WIDTH + len(href)
        elif print_alternative:
            text = f"{text} {href}"

    if width:
        text = text.ljust(width)

    # Coloring has to occur after justification
    if is_rendered:
        text = style(text, fg=Colors.LINK)

    return text
    def from_pty(cls, stdout: TextIO, term: Optional[str] = None) -> 'Vt100_Output':
        """
        Create an Output class from a pseudo terminal.
        (This will take the dimensions by reading the pseudo
        terminal attributes.)
        """
        # Normally, this requires a real TTY device, but people instantiate
        # this class often during unit tests as well. For convenience, we print
        # an error message, use standard dimensions, and go on.
        isatty = stdout.isatty()
        fd = stdout.fileno()

        if not isatty and fd not in cls._fds_not_a_terminal:
            msg = 'Warning: Output is not to a terminal (fd=%r).\n'
            sys.stderr.write(msg % fd)
            cls._fds_not_a_terminal.add(fd)

        def get_size() -> Size:
            # If terminal (incorrectly) reports its size as 0, pick a
            # reasonable default.  See
            # https://github.com/ipython/ipython/issues/10071
            rows, columns = (None, None)

            if isatty:
                rows, columns = _get_size(stdout.fileno())
            return Size(rows=rows or 24, columns=columns or 80)

        return cls(stdout, get_size, term=term)
Exemplo n.º 6
0
    def from_pty(cls, stdout: TextIO, term: Optional[str] = None) -> "Vt100_Output":
        """
        Create an Output class from a pseudo terminal.
        (This will take the dimensions by reading the pseudo
        terminal attributes.)
        """
        # Normally, this requires a real TTY device, but people instantiate
        # this class often during unit tests as well. For convenience, we print
        # an error message, use standard dimensions, and go on.
        fd = stdout.fileno()

        if not stdout.isatty() and fd not in cls._fds_not_a_terminal:
            msg = "Warning: Output is not a terminal (fd=%r).\n"
            sys.stderr.write(msg % fd)
            cls._fds_not_a_terminal.add(fd)

        def get_size() -> Size:
            # If terminal (incorrectly) reports its size as 0, pick a
            # reasonable default.  See
            # https://github.com/ipython/ipython/issues/10071
            rows, columns = (None, None)

            # It is possible that `stdout` is no longer a TTY device at this
            # point. In that case we get an `OSError` in the ioctl call in
            # `get_size`. See:
            # https://github.com/prompt-toolkit/python-prompt-toolkit/pull/1021
            try:
                rows, columns = _get_size(stdout.fileno())
            except OSError:
                pass
            return Size(rows=rows or 24, columns=columns or 80)

        return cls(stdout, get_size, term=term)
Exemplo n.º 7
0
def should_do_markup(file: TextIO) -> bool:
    if os.environ.get("PY_COLORS") == "1":
        return True
    if os.environ.get("PY_COLORS") == "0":
        return False
    return (hasattr(file, "isatty") and file.isatty()
            and os.environ.get("TERM") != "dumb"
            and not (sys.platform.startswith("java") and os._name == "nt"))
Exemplo n.º 8
0
def _output(level: int, fp: TextIO, header: Text, color: Text,
            message: object):
    if level < LOG_LEVEL:
        return
    if fp.isatty():
        fp.write(f'{color}({header}){Fore.RESET} {message}\n')
    else:
        fp.write(f'({header}) {message}\n')
Exemplo n.º 9
0
def cprint(*args,
           fg: Optional[ColorType] = None,
           bg: Optional[ColorType] = None,
           file: TextIO = sys.stdout,
           only_tty: bool = True,
           **kwargs) -> None:
    if _DO_COLOR and (not only_tty or (only_tty and file.isatty())):
        args = incolor(*args, fg=fg, bg=bg, join=False)
    print(*args, file=file, **kwargs)
Exemplo n.º 10
0
def _output(level: int, fp: TextIO, header: Text, color: Text,
            message: object):
    if level < LOG_LEVEL:
        return

    proc_name = '' if PROC_NAME is None else f'/"{PROC_NAME}"'
    if fp.isatty():
        fp.write(f'{color}({header}{proc_name}){Fore.RESET} {message}\n')
    else:
        fp.write(f'({header}{proc_name}) {message}\n')
    fp.flush()
Exemplo n.º 11
0
 def supports_color(self, ostr: TextIO) -> bool:
     """
     Returns True if the running system's terminal supports color, and False
     otherwise.
     """
     unsupported_platform = (sys.platform in ('win32', 'Pocket PC'))
     # isatty is not always implemented, #6223.
     is_a_tty = hasattr(ostr, 'isatty') and ostr.isatty()
     if unsupported_platform or not is_a_tty:
         return False
     return True
Exemplo n.º 12
0
def should_do_markup(file: TextIO) -> bool:
    if os.environ.get("PY_COLORS") == "1":
        return True
    if os.environ.get("PY_COLORS") == "0":
        return False
    if "NO_COLOR" in os.environ:
        return False
    if "FORCE_COLOR" in os.environ:
        return True
    return (hasattr(file, "isatty") and file.isatty()
            and os.environ.get("TERM") != "dumb")
Exemplo n.º 13
0
def dump_version_info(f: TextIO) -> None:
    if f.isatty():
        return
    print(
        'dump_version_info: dumping information about the current commit and working directory',
        file=f)
    run_isolated_process(['git', 'rev-parse', 'HEAD'], f)
    run_isolated_process(['git', 'status'], f)
    run_isolated_process(['git', 'diff'], f)
    run_isolated_process(['git', 'diff', '--cached'], f)
    print('dump_version_info: done.', file=f)
    print('-' * 80, file=f)
Exemplo n.º 14
0
def supports_ansi(file_: TextIO) -> bool:
    try:
        import winreg
        key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Console')
        win_reg_ok = winreg.QueryValueEx(key, 'VirtualTerminalLevel')[0] == 1
    except (ModuleNotFoundError, FileNotFoundError):
        win_reg_ok = False

    return hasattr(file_, 'isatty') and file_.isatty() and (
        sys.platform != 'win32' or win_reg_ok or 'WT_SESSION' in os.environ
        or os.environ.get('TERM_PROGRAM', '') == 'vscode'
        or 'ANSICON' in os.environ)
Exemplo n.º 15
0
def write(message: str,
          colour: str = NORMAL,
          stream: TextIO = sys.stdout) -> None:
    # Lets check if we're writing to a TTY before colouring
    should_colour = False
    try:
        should_colour = stream.isatty()
    except AttributeError:
        # Just in case `isatty` isn't defined on everything. The python
        # docs are incredibly vague.
        pass

    if not should_colour:
        stream.write(message + "\n")
    else:
        stream.write(colour + message + NORMAL + "\n")
Exemplo n.º 16
0
def terminal_ansi(stream: tp.TextIO = sys.stdout) -> bool:
    '''
    Return True if the terminal is ANSI color compatible.
    '''
    environ = os.environ
    if 'ANSICON' in environ or 'PYCHARM_HOSTED' in environ:
        return True #pragma: no cover
    if 'TERM' in environ and environ['TERM'] == 'ANSI':
        return True #pragma: no cover
    if 'INSIDE_EMACS' in environ:
        return False #pragma: no cover

    if getattr(stream, 'closed', False): # if has closed attr and closed
        return False #pragma: no cover

    if hasattr(stream, 'isatty') and stream.isatty() and platform.system() != 'Windows':
        return True #pragma: no cover

    return False
Exemplo n.º 17
0
    def pretty(text, has_color=None, is_bold=False, is_end=True, out_file: TextIO=sys.stdout):
        """Print colored message to the specified file."""

        if out_file.isatty():
            attrs = []

            if has_color:
                attrs.append(str(has_color.value))

            if is_bold:
                attrs.append('1')

            if len(attrs) > 0:
                message = u'\x1b[{}m{}\x1b[0m'.format(';'.join(attrs), text)

        if is_end:
            print(text, file=out_file)
        else:
            print(text, file=out_file, end='')
            out_file.flush()
Exemplo n.º 18
0
def setup_logging(stream: TextIO, log_level: int, exit_level: int):
    """Set up the root logger.

    Uses color if the stream is not a TTY. The log_level must not be higher than
    exit_level (exiting before printing makes no sense), and the exit_level must
    not be higher than FATAL (fatal logs should always cause an exit).
    """
    assert log_level <= exit_level
    assert exit_level <= logging.FATAL
    logger = logging.getLogger()
    logger.setLevel(log_level)
    handler = ExitStreamHandler(sys.stderr, exit_level)
    handler.setFormatter(ColorFormatter(use_color=stream.isatty()))
    logger.addHandler(handler)
    # FATAL and CRITICAL are the same. I prefer the label FATAL.
    logging.addLevelName(logging.FATAL, "FATAL")
    # Disable extra logs generated by the live server.
    disable_logger("asyncio")
    disable_logger("livereload")
    disable_logger("tornado")
Exemplo n.º 19
0
    def __init__(self, stdin: TextIO) -> None:
        # Test whether the given input object has a file descriptor.
        # (Idle reports stdin to be a TTY, but fileno() is not implemented.)
        try:
            # This should not raise, but can return 0.
            stdin.fileno()
        except io.UnsupportedOperation as e:
            if "idlelib.run" in sys.modules:
                raise io.UnsupportedOperation(
                    "Stdin is not a terminal. Running from Idle is not supported."
                ) from e
            else:
                raise io.UnsupportedOperation(
                    "Stdin is not a terminal.") from e

        # Even when we have a file descriptor, it doesn't mean it's a TTY.
        # Normally, this requires a real TTY device, but people instantiate
        # this class often during unit tests as well. They use for instance
        # pexpect to pipe data into an application. For convenience, we print
        # an error message and go on.
        isatty = stdin.isatty()
        fd = stdin.fileno()

        if not isatty and fd not in Vt100Input._fds_not_a_terminal:
            msg = "Warning: Input is not a terminal (fd=%r).\n"
            sys.stderr.write(msg % fd)
            sys.stderr.flush()
            Vt100Input._fds_not_a_terminal.add(fd)

        #
        self.stdin = stdin

        # Create a backup of the fileno(). We want this to work even if the
        # underlying file is closed, so that `typeahead_hash()` keeps working.
        self._fileno = stdin.fileno()

        self._buffer: List[KeyPress] = []  # Buffer to collect the Key objects.
        self.stdin_reader = PosixStdinReader(self._fileno,
                                             encoding=stdin.encoding)
        self.vt100_parser = Vt100Parser(
            lambda key_press: self._buffer.append(key_press))
Exemplo n.º 20
0
def compare_stats(results_old: AnalysisRun,
                  results_new: AnalysisRun,
                  out: TextIO = sys.stdout):
    stats_old = derive_stats(results_old)
    stats_new = derive_stats(results_new)

    old_keys = set(stats_old.keys())
    new_keys = set(stats_new.keys())
    keys = sorted(old_keys & new_keys)

    for key in keys:
        out.write(f"{key}\n")

        nested_keys = sorted(set(stats_old[key]) & set(stats_new[key]))

        for nested_key in nested_keys:
            val_old = float(stats_old[key][nested_key])
            val_new = float(stats_new[key][nested_key])

            report = f"{val_old:.3f} -> {val_new:.3f}"

            # Only apply highlighting when writing to TTY and it's not Windows
            if out.isatty() and os.name != 'nt':
                if val_new != 0:
                    ratio = (val_new - val_old) / val_new
                    if ratio < -0.2:
                        report = Colors.GREEN + report + Colors.CLEAR
                    elif ratio > 0.2:
                        report = Colors.RED + report + Colors.CLEAR

            out.write(f"\t {nested_key} {report}\n")

    removed_keys = old_keys - new_keys
    if removed_keys:
        out.write(f"REMOVED statistics: {removed_keys}\n")

    added_keys = new_keys - old_keys
    if added_keys:
        out.write(f"ADDED statistics: {added_keys}\n")

    out.write("\n")
Exemplo n.º 21
0
def pretty(message: str, color: Color = None, bold: bool = False,
           endl: bool = True, out_file: TextIO = sys.stdout) -> None:
    """Print colored message to the specified file."""
    msg = message

    if out_file.isatty():
        attrs = []

        if color:
            attrs.append(str(color.value))

        if bold:
            attrs.append('1')

        if len(attrs) > 0:
            msg = u'\x1b[{}m{}\x1b[0m'.format(';'.join(attrs), msg)

    if endl:
        print(msg, file=out_file)
    else:
        print(msg, file=out_file, end='')
        out_file.flush()
Exemplo n.º 22
0
    def __init__(self, stdin: TextIO) -> None:
        # Test whether the given input object has a file descriptor.
        # (Idle reports stdin to be a TTY, but fileno() is not implemented.)
        try:
            # This should not raise, but can return 0.
            stdin.fileno()
        except io.UnsupportedOperation:
            if 'idlelib.run' in sys.modules:
                raise io.UnsupportedOperation(
                    'Stdin is not a terminal. Running from Idle is not supported.')
            else:
                raise io.UnsupportedOperation('Stdin is not a terminal.')

        # Even when we have a file descriptor, it doesn't mean it's a TTY.
        # Normally, this requires a real TTY device, but people instantiate
        # this class often during unit tests as well. They use for instance
        # pexpect to pipe data into an application. For convenience, we print
        # an error message and go on.
        isatty = stdin.isatty()
        fd = stdin.fileno()

        if not isatty and fd not in Vt100Input._fds_not_a_terminal:
            msg = 'Warning: Input is not to a terminal (fd=%r).\n'
            sys.stderr.write(msg % fd)
            Vt100Input._fds_not_a_terminal.add(fd)

        #
        self.stdin = stdin

        # Create a backup of the fileno(). We want this to work even if the
        # underlying file is closed, so that `typeahead_hash()` keeps working.
        self._fileno = stdin.fileno()

        self._buffer: List[KeyPress] = []  # Buffer to collect the Key objects.
        self.stdin_reader = PosixStdinReader(self._fileno)
        self.vt100_parser = Vt100Parser(
            lambda key_press: self._buffer.append(key_press))
Exemplo n.º 23
0
Arquivo: ansi.py Projeto: ydlr/nixops
def ansi_warn(s: str, outfile: TextIO = sys.stderr) -> str:
    return "\033[1;33m" + s + "\033[0m" if outfile.isatty() else s
Exemplo n.º 24
0
def create_indent_writer(stream: TextIO) -> IndentWriter:
    return ColorIndentWriter(stream) if stream.isatty() else IndentWriter(
        stream)
Exemplo n.º 25
0
def create_writer(stream: TextIO) -> Writer:
    return ColorWriter(stream) if stream.isatty() else Writer(stream)
Exemplo n.º 26
0
Arquivo: ansi.py Projeto: ydlr/nixops
def ansi_success(s: str, outfile: TextIO = sys.stderr) -> str:
    return "\033[1;32m" + s + "\033[0m" if outfile.isatty() else s
Exemplo n.º 27
0
 def __new__(cls, stream: typing.TextIO) -> logging.StreamHandler:
     """Automatically fallback to normal handler if requirement not satisfied."""
     if not stream.isatty() or not importlib.util.find_spec("tqdm"):
         return logging.StreamHandler(stream)
     return super().__new__(cls)
Exemplo n.º 28
0
    async def read_and_write_stream(self, input_stream: asyncio.StreamReader, output_filename: str,
                                    output_stream: TextIO=sys.stdout) -> None:
        """read the output of the `input_stream` and then write it into `output_filename` and `output_stream`"""
        def delete_ansi_escape(text: str) -> str:
            ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
            return ansi_escape.sub('', text)

        def prepare_for_print(out: bytes) -> str:
            # errors='ignore' is here because some chips produce some garbage bytes
            result = out.decode(errors='ignore')
            if not output_stream.isatty():
                # delete escape sequence if we printing in environments where ANSI coloring is disabled
                return delete_ansi_escape(result)
            return result

        def print_progression(output: str) -> None:
            # Print a new line on top of the previous line
            sys.stdout.write('\x1b[K')
            print('\r', end='')
            print(fit_text_in_terminal(output.strip('\n\r')), end='', file=output_stream)

        try:
            with open(output_filename, 'w') as output_file:
                while True:
                    out = await input_stream.readline()
                    if not out:
                        break
                    output = prepare_for_print(out)
                    output_file.write(output)

                    # print output in progression way but only the progression related (that started with '[') and if verbose flag is not set
                    if self.force_progression and output[0] == '[' and '-v' not in self.args and output_stream.isatty():
                        print_progression(output)
                    else:
                        print(output, end='', file=output_stream)
        except (RuntimeError, EnvironmentError) as e:
            yellow_print('WARNING: The exception {} was raised and we can\'t capture all your {} and '
                         'hints on how to resolve errors can be not accurate.'.format(e, output_stream.name.strip('<>')))
Exemplo n.º 29
0
 def print_label(self, to: TextIO) -> None:
     label = "\n => {} <= \n\n".format(self.label)
     if to.isatty():
         label = colorize(label, self.color, True)
     to.write(label)
Exemplo n.º 30
0
Arquivo: ansi.py Projeto: ydlr/nixops
def ansi_highlight(s: str, outfile: TextIO = sys.stderr) -> str:
    return "\033[1;35m" + s + "\033[0m" if outfile.isatty() else s
Exemplo n.º 31
0
def tabulate(
        headings: Sequence[str],
        data: Any,
        key: Callable = None,
        sorting: int = 0,
        quiet: Optional[bool] = None,
        out: TextIO = None):
    """
    Prints tabulated data, with the given headings.

    This function is not resilient -- the headings and data must have
    the same count of rows, nothing will inject empty values.

    Output will be configured to set the columns to their maximum
    width necessary for the longest value from all the rows or the
    heading.

    :param headings: The column titles

    :param data: Rows of data

    :param key: Transformation to apply to each row of data to get the
      actual individual columns. Should be a unary function. Default,
      data is iterated as-is.

    :param sorting: Whether data rows should be sorted and in what
      direction. 0 for no sorting, 1 for ascending, -1 for
      descending. If key is specified, then sorting will be based on
      those transformations. Default, no sorting.

    :param quiet: Whether to print headings or not. Default, only print
      headings if out is a TTY device.

    :param out: Stream to write output to. Default, `sys.stdout`
    """

    if out is None:
        out = sys.stdout

    # The quiet setting has three values. True meaning no header,
    # False meaning header, and None meaning no header if out is not a
    # TTY.
    if quiet is None:
        quiet = not out.isatty()

    if key is not None:
        if not callable(key):
            key = itemgetter(key)

        # convert data to a list, and apply the key if necessary to find
        # the real columns
        data = map(key, data)

    if sorting:
        data = sorted(data, reverse=(sorting < 0))
    else:
        data = list(data)

    # now we need to compute the maximum width of each columns
    if data:
        widths = [max(len(str(v)) for v in col)
                  for col in zip_longest(*data, fillvalue="")]
    else:
        widths = []

    if headings and not quiet:
        widths = [max(w or 0, len(h or "")) for w, h in
                  zip_longest(widths, headings)]

    # now we create the format string based on the max width of each
    # column plus some spacing.
    fmt = "  ".join(f"{{!s:<{w}}}" for w in widths)

    if headings and not quiet:
        print(fmt.format(*headings), file=out)
        print("  ".join(("-" * h) for h in widths), file=out)

    for row in data:
        print(fmt.format(*row), file=out)
Exemplo n.º 32
0
 def __new__(cls, stream: TextIO):
     sb = stream.buffer
     if stream.isatty() or sb.isatty():
         return sb
     return super().__new__(cls)