Skip to content

ezpz.log⚓︎

ezpz/log/init.py

Console ⚓︎

Bases: Console

Extends rich Console class.

Source code in src/ezpz/log/console.py
class Console(rich_console.Console):
    """Extends rich Console class."""

    def __init__(self, *args: str, redirect: bool = True, **kwargs: Any) -> None:
        """
        enrich console does soft-wrapping by default and this diverge from
        original rich console which does not, creating hard-wraps instead.
        """
        self.redirect = redirect

        if "soft_wrap" not in kwargs:
            kwargs["soft_wrap"] = True

        if "theme" not in kwargs:
            kwargs["theme"] = get_theme()

        if "markup" not in kwargs:
            kwargs["markup"] = True

        if "width" not in kwargs:
            kwargs["width"] = 55510

        # Unless user already mentioning terminal preference, we use our
        # heuristic to make an informed decision.
        if "force_terminal" not in kwargs:
            kwargs["force_terminal"] = should_do_markup(
                stream=kwargs.get("file", sys.stdout)
            )
        if "force_jupyter" not in kwargs:
            kwargs["force_jupyter"] = is_interactive()

        super().__init__(*args, **kwargs)
        self.extended = True

        if self.redirect:
            if not hasattr(sys.stdout, "rich_proxied_file"):
                sys.stdout = FileProxy(self, sys.stdout)  # type: ignore
            if not hasattr(sys.stderr, "rich_proxied_file"):
                sys.stderr = FileProxy(self, sys.stderr)  # type: ignore

    # https://github.com/python/mypy/issues/4441
    def print(self, *args, **kwargs) -> None:  # type: ignore
        """Print override that respects user soft_wrap preference."""
        # Currently rich is unable to render ANSI escapes with print so if
        # we detect their presence, we decode them.
        # https://github.com/willmcgugan/rich/discussions/404
        if args and isinstance(args[0], str) and "\033" in args[0]:
            text = format(*args) + "\n"
            decoder = AnsiDecoder()
            args = list(decoder.decode(text))  # type: ignore
        super().print(*args, **kwargs)

__init__(*args, redirect=True, **kwargs) ⚓︎

enrich console does soft-wrapping by default and this diverge from original rich console which does not, creating hard-wraps instead.

Source code in src/ezpz/log/console.py
def __init__(self, *args: str, redirect: bool = True, **kwargs: Any) -> None:
    """
    enrich console does soft-wrapping by default and this diverge from
    original rich console which does not, creating hard-wraps instead.
    """
    self.redirect = redirect

    if "soft_wrap" not in kwargs:
        kwargs["soft_wrap"] = True

    if "theme" not in kwargs:
        kwargs["theme"] = get_theme()

    if "markup" not in kwargs:
        kwargs["markup"] = True

    if "width" not in kwargs:
        kwargs["width"] = 55510

    # Unless user already mentioning terminal preference, we use our
    # heuristic to make an informed decision.
    if "force_terminal" not in kwargs:
        kwargs["force_terminal"] = should_do_markup(
            stream=kwargs.get("file", sys.stdout)
        )
    if "force_jupyter" not in kwargs:
        kwargs["force_jupyter"] = is_interactive()

    super().__init__(*args, **kwargs)
    self.extended = True

    if self.redirect:
        if not hasattr(sys.stdout, "rich_proxied_file"):
            sys.stdout = FileProxy(self, sys.stdout)  # type: ignore
        if not hasattr(sys.stderr, "rich_proxied_file"):
            sys.stderr = FileProxy(self, sys.stderr)  # type: ignore

print(*args, **kwargs) ⚓︎

Print override that respects user soft_wrap preference.

Source code in src/ezpz/log/console.py
def print(self, *args, **kwargs) -> None:  # type: ignore
    """Print override that respects user soft_wrap preference."""
    # Currently rich is unable to render ANSI escapes with print so if
    # we detect their presence, we decode them.
    # https://github.com/willmcgugan/rich/discussions/404
    if args and isinstance(args[0], str) and "\033" in args[0]:
        text = format(*args) + "\n"
        decoder = AnsiDecoder()
        args = list(decoder.decode(text))  # type: ignore
    super().print(*args, **kwargs)

FluidLogRender ⚓︎

Renders log by not using columns and avoiding any wrapping.

Source code in src/ezpz/log/handler.py
class FluidLogRender:  # pylint: disable=too-few-public-methods
    """Renders log by not using columns and avoiding any wrapping."""

    def __init__(
        self,
        show_time: bool = True,
        show_level: bool = True,
        show_path: bool = True,
        time_format: str | None = None,
        link_path: Optional[bool] = False,
        rank: Optional[int | str] = None,
    ) -> None:
        self.show_time = show_time
        self.show_level = show_level
        self.show_path = show_path
        self.time_format = time_format
        self.link_path = link_path
        self.rank = rank
        self._last_time: Optional[str] = None
        self.colorized = use_colored_logs()
        self.styles = get_styles(colorized=self.colorized)
        self.colored_prefix = EZPZ_LOG_USE_COLORED_PREFIX

    def _ps(self, key: str) -> str:
        """Return the prefix style for *key*, or empty if prefix color is off."""
        return self.styles.get(key, "") if self.colored_prefix else ""

    # Helpers for bracket modes
    def _open(self, result: Text) -> None:
        result.append(Text("[", style=self._ps("log.brace")))

    def _close(self, result: Text) -> None:
        result.append(Text("]", style=self._ps("log.brace")))

    def __call__(  # pylint: disable=too-many-arguments
        self,
        console: Console,  # type: ignore
        renderables: Iterable[ConsoleRenderable],
        log_time: Optional[datetime] = None,
        time_format: str | None = None,
        level: TextType = "",
        path: Optional[str] = None,
        line_no: Optional[int] = None,
        link_path: Optional[str] = None,
        funcName: Optional[str] = None,
    ) -> Text:
        # Resolve bracket mode once:
        #   "full"   -> each component wrapped: [time][level][path]
        #   "single" -> one wrapper:            [time level path]
        #   "none"   -> no brackets:            time level path -- msg
        if EZPZ_LOG_USE_BRACKETS:
            bmode = "full"
        elif EZPZ_LOG_USE_SINGLE_BRACKET:
            bmode = "single"
        else:
            bmode = "none"

        result = Text()
        has_prefix = False

        # -- Rank --
        if self.rank is not None or EZPZ_LOG_SHOW_RANK:
            rank_val = self.rank if self.rank is not None else get_rank()
            self._open(result)
            result += Text(f"{rank_val}", style=self._ps("log.rank"))
            self._close(result)
            has_prefix = True

        # Open single bracket (wraps everything until the final close)
        if bmode == "single":
            self._open(result)

        # -- Time --
        if self.show_time and EZPZ_LOG_SHOW_TIME:
            log_time = datetime.now() if log_time is None else log_time
            log_time_display = log_time.strftime(
                time_format or self.time_format or EZPZ_LOG_TIME_FORMAT
            )
            if bmode == "full":
                self._open(result)
            if EZPZ_LOG_DAY_TIME_SEPARATOR in log_time_display:
                d, t = log_time_display.split(EZPZ_LOG_DAY_TIME_SEPARATOR)
                result += Text(d, style=self._ps("log.day_color"))
                result += Text(
                    EZPZ_LOG_DAY_TIME_SEPARATOR,
                    style=self._ps("repr.colon"),
                )
                result += Text(t, style=self._ps("log.time_color"))
            else:
                result += Text(
                    log_time_display,
                    style=self._ps("log.time_color"),
                )
            if bmode == "full":
                self._close(result)
            else:
                result += Text(" ")
            self._last_time = log_time_display
            has_prefix = True

        # -- Level --
        if self.show_level and EZPZ_LOG_SHOW_LEVEL:
            if isinstance(level, Text):
                lstr = level.plain.rstrip(" ")[0]
                lstyle = (
                    level.spans[0].style
                    if self.colorized and self.colored_prefix and level.spans
                    else Style.null()
                )
                level.spans = [Span(0, len(lstr), lstyle)]
            elif isinstance(level, str):
                lstr = level.rstrip(" ")[0]
                lstyle = (
                    f"logging.level.{lstr}"
                    if self.colorized and self.colored_prefix
                    else Style.null()
                )
            else:
                lstr = str(level)
                lstyle = Style.null()
            show_path = (self.show_path and EZPZ_LOG_SHOW_PATH) and path
            if bmode == "full":
                ltext = (
                    Text("[", style=self._ps("log.brace"))
                    + Text(lstr, style=lstyle)
                    + Text("]", style=self._ps("log.brace"))
                )
            elif show_path:
                ltext = Text(lstr, style=lstyle) + Text(" ")
            else:
                ltext = Text(lstr, style=lstyle)
            result += ltext
            has_prefix = True

        # -- Path --
        if (self.show_path and EZPZ_LOG_SHOW_PATH) and path:
            path_text = Text()
            if bmode == "full":
                self._open(path_text)
            text_arr = []
            if "/" in path:
                parent, remainder = path.rsplit("/", 1)
            else:
                parent, remainder = "", path
            if "." in remainder:
                module, *fn = remainder.split(".")
                fn = ".".join(fn)
            else:
                module = remainder
                fn = None
            if funcName is not None:
                fn = funcName
            text_arr += [
                Text(parent, style=self._ps("log.parent")),
                Text("/"),
                Text(module, style=self._ps("log.path")),
            ]
            if line_no:
                text_arr += [
                    Text(":", style=self._ps("repr.colon")),
                    Text(
                        f"{line_no}",
                        style=self._ps("log.linenumber"),
                    ),
                ]
            if fn is not None:
                text_arr += [
                    Text(":"),
                    Text(fn, style=self._ps("repr.function")),
                ]
            path_text.append(Text.join(Text(""), text_arr))
            if bmode == "full":
                self._close(path_text)
            result += path_text
            has_prefix = True

        # -- Close wrapper / separator before message --
        if bmode == "single":
            self._close(result)
            if has_prefix:
                result += Text(" ")
        elif has_prefix:
            if bmode == "none":
                result += Text(" -- ", style=self._ps("repr.dash"))
            else:
                result += Text(" ")

        # -- Message --
        for elem in renderables:
            if ANSI_ESCAPE_PATTERN.search(str(elem)):
                result += Text.from_ansi(str(elem))
            else:
                result += elem

        return result

RichHandler ⚓︎

Bases: RichHandler

Enriched handler that does not wrap.

Source code in src/ezpz/log/handler.py
class RichHandler(OriginalRichHandler):
    """Enriched handler that does not wrap."""

    def __init__(
        self, rank: Optional[int | str] = None, *args: Any, **kwargs: Any
    ) -> None:
        if "console" not in kwargs:
            console = get_console(
                redirect=False,
                width=9999,
                markup=use_colored_logs(),
                soft_wrap=False,
            )
            kwargs["console"] = console
            self.__console = console
        else:
            self.__console = kwargs["console"]
        # Use ezpz's custom highlighter so `(±std)` tokens emitted by
        # `format_compact_summary` get the orange `repr.ezpz_std` style
        # instead of being swallowed by rich's defaults.
        if "highlighter" not in kwargs:
            from ezpz.log.highlighter import EzpzReprHighlighter

            kwargs["highlighter"] = EzpzReprHighlighter()
        super().__init__(*args, **kwargs)
        # RichHandler constructor does not allow custom renderer
        # https://github.com/willmcgugan/rich/issues/438
        self._log_render = FluidLogRender(
            show_time=kwargs.get("show_time", True),
            show_level=kwargs.get("show_level", True),
            show_path=kwargs.get("show_path", True),
            link_path=kwargs.get("enable_link_path", False),
            rank=rank,
        )

    def render(
        self,
        *,
        record: LogRecord,
        traceback: Optional[Any],
        message_renderable: "ConsoleRenderable",
    ) -> "ConsoleRenderable":
        """Render log for display.

        Args:
            record (LogRecord): logging Record.
            traceback (Optional[Traceback]): Traceback instance or None for no Traceback.
            message_renderable (ConsoleRenderable): Renderable (typically Text) containing log message contents.

        Returns:
            ConsoleRenderable: Renderable to display log.
        """
        fp = getattr(record, "pathname", None)
        parent = Path(fp).parent.as_posix().split("/")[-1] if fp else None
        module = getattr(record, "module", None)
        name = getattr(record, "name", None)
        # funcName = getattr(record, "funcName", None)
        parr = []
        if fp is not None:
            fp = Path(fp)
            parent = fp.parent.as_posix().split("/")[-1]
            parr.append(parent)
        if module is not None:
            parr.append(module)

        if (
            name is not None
            and parent is not None
            and f"{parent}.{module}" != name
        ):
            parr.append(name)
        pstr = "/".join([parr[0], ".".join(parr[1:])])
        level = self.get_level_text(record)
        time_format = (
            None if self.formatter is None else self.formatter.datefmt
        )
        # default_time_fmt = "%Y%m%d@%H:%M:%S,%f"
        # default_time_fmt = "%Y-%m-%d %H:%M:%S"  # .%f'
        time_format = time_format if time_format else EZPZ_LOG_TIME_FORMAT
        log_time = datetime.fromtimestamp(record.created)

        log_renderable = self._log_render(
            self.__console,
            (
                [message_renderable]
                if not traceback
                else [message_renderable, traceback]
            ),
            log_time=log_time,
            time_format=time_format,
            level=level,
            path=pstr,  # getattr(record, "pathname", None),
            line_no=record.lineno,
            link_path=record.pathname if self.enable_link_path else None,
            funcName=record.funcName,
        )
        return log_renderable

render(*, record, traceback, message_renderable) ⚓︎

Render log for display.

Parameters:

Name Type Description Default
record LogRecord

logging Record.

required
traceback Optional[Traceback]

Traceback instance or None for no Traceback.

required
message_renderable ConsoleRenderable

Renderable (typically Text) containing log message contents.

required

Returns:

Name Type Description
ConsoleRenderable ConsoleRenderable

Renderable to display log.

Source code in src/ezpz/log/handler.py
def render(
    self,
    *,
    record: LogRecord,
    traceback: Optional[Any],
    message_renderable: "ConsoleRenderable",
) -> "ConsoleRenderable":
    """Render log for display.

    Args:
        record (LogRecord): logging Record.
        traceback (Optional[Traceback]): Traceback instance or None for no Traceback.
        message_renderable (ConsoleRenderable): Renderable (typically Text) containing log message contents.

    Returns:
        ConsoleRenderable: Renderable to display log.
    """
    fp = getattr(record, "pathname", None)
    parent = Path(fp).parent.as_posix().split("/")[-1] if fp else None
    module = getattr(record, "module", None)
    name = getattr(record, "name", None)
    # funcName = getattr(record, "funcName", None)
    parr = []
    if fp is not None:
        fp = Path(fp)
        parent = fp.parent.as_posix().split("/")[-1]
        parr.append(parent)
    if module is not None:
        parr.append(module)

    if (
        name is not None
        and parent is not None
        and f"{parent}.{module}" != name
    ):
        parr.append(name)
    pstr = "/".join([parr[0], ".".join(parr[1:])])
    level = self.get_level_text(record)
    time_format = (
        None if self.formatter is None else self.formatter.datefmt
    )
    # default_time_fmt = "%Y%m%d@%H:%M:%S,%f"
    # default_time_fmt = "%Y-%m-%d %H:%M:%S"  # .%f'
    time_format = time_format if time_format else EZPZ_LOG_TIME_FORMAT
    log_time = datetime.fromtimestamp(record.created)

    log_renderable = self._log_render(
        self.__console,
        (
            [message_renderable]
            if not traceback
            else [message_renderable, traceback]
        ),
        log_time=log_time,
        time_format=time_format,
        level=level,
        path=pstr,  # getattr(record, "pathname", None),
        line_no=record.lineno,
        link_path=record.pathname if self.enable_link_path else None,
        funcName=record.funcName,
    )
    return log_renderable

get_active_enrich_handlers(logger) ⚓︎

Return (index, handler) pairs for active RichHandler instances.

Source code in src/ezpz/log/__init__.py
def get_active_enrich_handlers(logger: logging.Logger) -> list:
    """Return ``(index, handler)`` pairs for active ``RichHandler`` instances."""
    from ezpz.log.handler import RichHandler as EnrichHandler

    return [
        (idx, h)
        for idx, h in enumerate(logger.handlers)
        if isinstance(h, EnrichHandler)
    ]

get_console_from_logger(logger) ⚓︎

Return the Console attached to logger or synthesise a new one.

Source code in src/ezpz/log/__init__.py
def get_console_from_logger(logger: logging.Logger) -> Console:
    """Return the ``Console`` attached to *logger* or synthesise a new one."""
    from ezpz.log.handler import RichHandler as EnrichHandler

    for handler in logger.handlers:
        if isinstance(handler, (RichHandler, EnrichHandler)):
            return handler.console  # type: ignore
    from ezpz.log.console import get_console

    return get_console()

get_enrich_logging_config_as_yaml(name='enrich', level='INFO') ⚓︎

Render the Enrich logging YAML snippet with the requested name/level.

Source code in src/ezpz/log/__init__.py
def get_enrich_logging_config_as_yaml(
    name: str = "enrich", level: str = "INFO"
) -> str:
    """Render the Enrich logging YAML snippet with the requested name/level."""
    return rf"""
    ---
    # version: 1
    handlers:
      {name}:
        (): ezpz.log.handler.RichHandler
        show_time: true
        show_level: true
        enable_link_path: false
        level: {level.upper()}
    root:
      handlers: [{name}]
    disable_existing_loggers: false
    ...
    """

get_file_logger(name=None, level='INFO', rank_zero_only=True, fname=None) ⚓︎

Create a file-backed logger, optionally emitting only on rank zero.

Source code in src/ezpz/log/__init__.py
def get_file_logger(
    name: Optional[str] = None,
    level: str = "INFO",
    rank_zero_only: bool = True,
    fname: Optional[str] = None,
    # rich_stdout: bool = True,
) -> logging.Logger:
    """Create a file-backed logger, optionally emitting only on rank zero."""
    # logging.basicConfig(stream=DummyTqdmFile(sys.stderr))
    import logging

    from ezpz.distributed import get_rank

    fname = "output" if fname is None else fname
    log = logging.getLogger(name)
    if rank_zero_only:
        fh = logging.FileHandler(f"{fname}.log")
        if get_rank() == 0:
            log.setLevel(level)
            fh.setLevel(level)
        else:
            log.setLevel("CRITICAL")
            fh.setLevel("CRITICAL")
    else:
        fh = logging.FileHandler(f"{fname}-{get_rank()}.log")
        log.setLevel(level)
        fh.setLevel(level)
    # create formatter and add it to the handlers
    formatter = logging.Formatter(
        "[%(asctime)s][%(name)s][%(levelname)s] - %(message)s"
    )
    fh.setFormatter(formatter)
    log.addHandler(fh)
    return log

get_logger(name=None, level=None, rank_zero_only=True, rank=None, colored_logs=True) ⚓︎

Return a logger initialised with the project's logging configuration.

Source code in src/ezpz/log/__init__.py
def get_logger(
    name: Optional[str] = None,
    level: Optional[str] = None,
    rank_zero_only: bool = True,
    rank: Optional[int | str] = None,
    colored_logs: Optional[bool] = True,
) -> logging.Logger:
    """Return a logger initialised with the project's logging configuration."""
    if rank is None and rank_zero_only:
        try:
            from ezpz.distributed import get_rank

            rank = get_rank()
        except (RuntimeError, ImportError):
            rank = 0
    assert rank is not None
    # if is_interactive():
    #     return get_rich_logger(name=name, level=level)
    ezpz_log_level = (
        os.environ.get("EZPZ_LOG_LEVEL", os.environ.get("LOG_LEVEL", "INFO"))
        if level is None
        else level
    )
    if not colored_logs:
        os.environ["NO_COLOR"] = "1"

    logging_config = get_logging_config(rank=int(rank))

    LOG_FROM_ALL_RANKS = os.environ.get(
        "LOG_FROM_ALL_RANKS", os.environ.get("EZPZ_LOG_FROM_ALL_RANKS")
    )
    if LOG_FROM_ALL_RANKS is not None and to_bool(LOG_FROM_ALL_RANKS):
        LOG_FROM_ALL_RANKS = True
        print(
            f"[{rank:>2}] Logging from all ranks at level {ezpz_log_level} enabled via EZPZ_LOG_FROM_ALL_RANKS"
        )
        logging_config["handlers"]["term"] |= {"rank": rank}

    logging.config.dictConfig(logging_config)
    logger = logging.getLogger(name if name is not None else __name__)
    if LOG_FROM_ALL_RANKS:
        logger.setLevel(ezpz_log_level)
        return logger

    elif rank_zero_only:
        if int(rank) == 0:
            logger.setLevel(ezpz_log_level)
        else:
            logger.setLevel("CRITICAL")
    else:
        logger.setLevel(ezpz_log_level)

    return logger

get_logger_new(name, level='INFO') ⚓︎

Return a logger configured solely via the Enrich YAML template.

Source code in src/ezpz/log/__init__.py
def get_logger_new(
    name: str,
    level: str = "INFO",
):
    """Return a logger configured solely via the Enrich YAML template."""
    import yaml

    config = yaml.safe_load(
        get_enrich_logging_config_as_yaml(name=name, level=level),
    )
    logging.config.dictConfig(config)
    log = logging.getLogger(name=name)
    log.setLevel(level)
    return log

get_rich_logger(name=None, level=None) ⚓︎

Return a logger backed by a single :class:RichHandler.

Source code in src/ezpz/log/__init__.py
def get_rich_logger(
    name: Optional[str] = None, level: Optional[str] = None
) -> logging.Logger:
    """Return a logger backed by a single :class:`RichHandler`."""
    from ezpz.distributed import get_world_size
    from ezpz.log.handler import RichHandler

    level = "INFO" if level is None else level
    # log: logging.Logger = get_logger(name=name, level=level)
    log = logging.getLogger(name)
    log.handlers = []
    console = get_console(
        markup=True,
        redirect=(get_world_size() > 1),
    )
    handler = RichHandler(
        level,
        rich_tracebacks=False,
        console=console,
        show_path=False,
        enable_link_path=False,
    )
    log.handlers = [handler]
    log.setLevel(level)
    return log

print_styles() ⚓︎

Print the configured logging styles (optionally exporting to HTML).

Source code in src/ezpz/log/__init__.py
def print_styles():
    """Print the configured logging styles (optionally exporting to HTML)."""
    import argparse

    parser = argparse.ArgumentParser()
    from rich.text import Text

    from ezpz.log.console import Console

    parser.add_argument(
        "--html", action="store_true", help="Export as HTML table"
    )
    args = parser.parse_args()
    html: bool = args.html
    from rich.table import Table

    console = Console(record=True, width=120) if html else Console()
    table = Table("Name", "Styling")
    for style_name, style in STYLES.items():
        table.add_row(Text(style_name, style=style), str(style))

    console.print(table)
    if html:
        outfile = "enrich_styles.html"
        print(f"Saving to `{outfile}`")
        with open(outfile, "w") as f:
            f.write(console.export_html(inline_styles=True))

print_styles_alt(html=False, txt=False) ⚓︎

Variant of :func:print_styles with HTML and plain-text exports.

Source code in src/ezpz/log/__init__.py
def print_styles_alt(
    html: bool = False,
    txt: bool = False,
):
    """Variant of :func:`print_styles` with HTML and plain-text exports."""
    from pathlib import Path

    from rich.table import Table
    from rich.text import Text

    from ezpz.log.console import get_console
    from ezpz.log.style import DEFAULT_STYLES

    console = get_console(record=html, width=150)
    table = Table("Name", "Styling")
    styles = DEFAULT_STYLES
    styles |= STYLES
    for style_name, style in styles.items():
        table.add_row(Text(style_name, style=style), str(style))
    console.print(table)
    if html:
        outfile = "ezpz_styles.html"
        print(f"Saving to `{outfile}`")
        with open(outfile, "w") as f:
            f.write(console.export_html(inline_styles=True))
    if txt:
        file1 = "ezpz_styles.txt"
        text = console.export_text()
        # with open(file1, "w") as file:
        with Path(file1).open("w") as file:
            file.write(text)

should_do_markup(stream=sys.stdout) ⚓︎

Decide about use of ANSI colors.

Source code in src/ezpz/log/console.py
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.lower() == "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 returning false if user uses an error stream coloring solution
    return stream.isatty()

silence_noisy_loggers(*, extra=None, level=logging.WARNING, silence_transformers=True) ⚓︎

Quiet third-party loggers that spam INFO during ML workloads.

By default raises the following loggers to WARNING:

- ``httpx`` (one INFO line per HF Hub request)
- ``huggingface_hub`` (resolve/redirect chatter)
- ``filelock`` (acquire/release on every cache hit)
- ``urllib3`` (connection pool diagnostics)

These are noisy enough to dominate the console output for any example that touches AutoTokenizer.from_pretrained or similar Hub calls (see fsdp_tp, hf, hf_trainer, inference). Each example used to duplicate this block locally — call this once at the top of main() instead.

Parameters:

Name Type Description Default
extra Optional[Sequence[str]]

additional logger names to also quiet. Useful for workload-specific spam (e.g. ("matplotlib.font_manager",)).

None
level int

target level (default logging.WARNING).

WARNING
silence_transformers bool

also raise transformers logging to ERROR and disable its progress bar. transformers is imported lazily inside the function so this is safe when the package isn't installed.

True

Idempotent — safe to call multiple times.

Source code in src/ezpz/log/__init__.py
def silence_noisy_loggers(
    *,
    extra: Optional[Sequence[str]] = None,
    level: int = logging.WARNING,
    silence_transformers: bool = True,
) -> None:
    """Quiet third-party loggers that spam INFO during ML workloads.

    By default raises the following loggers to ``WARNING``:

        - ``httpx`` (one INFO line per HF Hub request)
        - ``huggingface_hub`` (resolve/redirect chatter)
        - ``filelock`` (acquire/release on every cache hit)
        - ``urllib3`` (connection pool diagnostics)

    These are noisy enough to dominate the console output for any
    example that touches ``AutoTokenizer.from_pretrained`` or similar
    Hub calls (see fsdp_tp, hf, hf_trainer, inference). Each example
    used to duplicate this block locally — call this once at the top
    of ``main()`` instead.

    Args:
        extra: additional logger names to also quiet. Useful for
            workload-specific spam (e.g. ``("matplotlib.font_manager",)``).
        level: target level (default ``logging.WARNING``).
        silence_transformers: also raise transformers logging to ERROR
            and disable its progress bar. ``transformers`` is imported
            lazily inside the function so this is safe when the package
            isn't installed.

    Idempotent — safe to call multiple times.
    """
    names = tuple(_DEFAULT_NOISY_LOGGERS) + tuple(extra or ())
    for name in names:
        logging.getLogger(name).setLevel(level)
    if silence_transformers:
        try:
            import transformers as _transformers
            _transformers.logging.set_verbosity_error()
            _transformers.logging.disable_progress_bar()
        except Exception:
            # transformers not installed; nothing to silence.
            pass

to_bool(value) ⚓︎

Return a bool for the arg.

Source code in src/ezpz/log/console.py
def to_bool(value: Any) -> bool:
    """Return a bool for the arg."""
    if value is None or isinstance(value, bool):
        return bool(value)
    if isinstance(value, str):
        value = value.lower()
    if value in ("yes", "on", "1", "true", 1):
        return True
    return False

use_colored_logs() ⚓︎

Return False when colour should be suppressed.

Follows the no-color.org <https://no-color.org>_ convention: colour is on by default and only disabled when NO_COLOR or NOCOLOR is set (to any non-empty value) or TERM is dumb / unknown.

Source code in src/ezpz/log/config.py
def use_colored_logs() -> bool:
    """Return ``False`` when colour should be suppressed.

    Follows the `no-color.org <https://no-color.org>`_ convention: colour is
    **on** by default and only disabled when ``NO_COLOR`` or ``NOCOLOR`` is set
    (to any non-empty value) or ``TERM`` is ``dumb`` / ``unknown``.
    """
    term = os.environ.get("TERM", "")
    if term in ("dumb", "unknown"):
        return False
    for var in ("NO_COLOR", "NOCOLOR"):
        val = os.environ.get(var)
        if val is not None and val != "":
            return False
    return True