failed NO_PATCH NO_PATCH UNSUBMITTED empty_patch(None) · None tool calls · 0 s · Textualize/rich
perf: reduce Console and RichHandler import time by deferring unused imports ## E2E Results | Import | master | This PR | Speedup | |---|---|---|---| | `from rich.console import Console` | 78.1ms | 52.2ms | **1.50x faster** | | `from rich.logging import RichHandler` | 99.4ms | 56.9ms | **1.75x faster** | | `import rich` | 18.2ms | 18.3ms | (already lean) | ## Summary Defer module-level imports that are only needed in specific code paths, move annotation-only imports to `TYPE_CHECKING`, and remove dead code: | File | Change | Savings | |---|---|---| | `logging.py` | Defer `Traceback` to `emit()` (only when `rich_tracebacks=True`) | ~20ms | | `logging.py` | `from __future__ import annotations` + `TYPE_CHECKING` for `Console`, `ConsoleRenderable`, `Highlighter`, `FormatTimeCallable` | ~6ms | | `logging.py` | Replace `pathlib.Path` → `os.path.basename` (also a minor runtime win) | ~4-5ms | | `console.py` | Eliminate `import inspect`; replace `isclass` → `isinstance(x, type)`, `currentframe` → `sys._getframe` | ~10ms | | `console.py` | Defer `pretty` to `Console.print()` | ~3-5ms | | `console.py` | Defer `scope` to `Console.log()` (only when `log_locals=True`) | ~3-5ms | | `console.py` | Defer `getpass` to `Console.input()` (only when `password=True`) | ~2ms | | `console.py` | Defer `html.escape` and `zlib` to export methods | ~2.3ms | | `console.py` | Remove dead `_svg_hash` function (unused since 113997ac, fixes latent NameError) | cleanup | | `segment.py` | Remove dead `logging` import (`getLogger` assigned but never used) | ~2-3ms | | `theme.py` | Defer `configparser` to `Theme.from_file()` | ~1.5ms | | `syntax.py` | Move `Console`, `ConsoleOptions`, `JustifyMethod`, `RenderResult` to `TYPE_CHECKING` | eliminates console.py from syntax import chain | | `protocol.py` | Replace `from inspect import isclass` → `isinstance(x, type)` | prepares for dataclasses removal | | `repr.py` | Defer `import inspect` to `auto_rich_repr()` | prepares for dataclasses removal | All deferred imports are still available at runtime — they're loaded when the code path that needs them is actually hit. The `TYPE_CHECKING` imports are annotation-only and never needed at runtime (files use `from __future__ import annotations`). ## Benchmarks Environment: Standard_D2s_v5 (non-burstable), CPython 3.13.13, hyperfine --min-runs 30 ### Per-module breakdown (this PR) | Module | Time | |---|---| | `import rich` | 18.2ms | | `Console` | 52.5ms | | `RichHandler` | 56.4ms | | `Syntax` | 64.7ms | | `Traceback` | 92.5ms | | `Markdown` | 103.0ms | ## Motivation pip vendors Rich, and `Console`/`RichHandler` are imported on every `pip` invocation. These savings directly improve startup time for pip and every other tool that imports Rich. ## Testing - `pytest tests/` — 952 passed, 25 skipped - `mypy -p rich --no-incremental` — no issues - `black --check` — passes ## Disclosure This PR was developed with AI assistance (codeflash-agent). Benchmarked in a controlled environment (dedicated non-burstable Azure VM). All tests verified across multiple Python implementations.
| # | Tool | Arguments | Result |
|---|---|---|---|
| No trace captured. | |||
..........................................F
=================================== FAILURES ===================================
_____________________________ test_input_password ______________________________
prompt = '', stream = None
def unix_getpass(prompt='Password: ', stream=None):
"""Prompt for a password, with echo turned off.
Args:
prompt: Written on stream to ask for the input. Default: 'Password: '
stream: A writable file object to display the prompt. Defaults to
the tty. If no tty is available defaults to sys.stderr.
Returns:
The seKr3t input.
Raises:
EOFError: If our input tty or stdin was closed.
GetPassWarning: When we were unable to turn echo off on the input.
Always restores terminal settings before returning.
"""
passwd = None
with contextlib.ExitStack() as stack:
try:
# Always try reading and writing directly on the tty first.
> fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
E OSError: [Errno 6] Device not configured: '/dev/tty'
/Users/jp/.local/share/uv/python/cpython-3.13.15-macos-aarch64-none/lib/python3.13/getpass.py:47: OSError
During handling of the above exception, another exception occurred:
prompt = '', stream = None
def unix_getpass(prompt='Password: ', stream=None):
"""Prompt for a password, with echo turned off.
Args:
prompt: Written on stream to ask for the input. Default: 'Password: '
stream: A writable file object to display the prompt. Defaults to
the tty. If no tty is available defaults to sys.stderr.
Returns:
The seKr3t input.
Raises:
EOFError: If our input tty or stdin was closed.
GetPassWarning: When we were unable to turn echo off on the input.
Always restores terminal settings before returning.
"""
passwd = None
with contextlib.ExitStack() as stack:
try:
# Always try reading and writing directly on the tty first.
fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
tty = io.FileIO(fd, 'w+')
stack.enter_context(tty)
input = io.TextIOWrapper(tty)
stack.enter_context(input)
if not stream:
stream = input
except OSError:
# If that fails, see if stdin can be controlled.
stack.close()
try:
> fd = sys.stdin.fileno()
E io.UnsupportedOperation: redirected stdin is pseudofile, has no fileno()
/Users/jp/.local/share/uv/python/cpython-3.13.15-macos-aarch64-none/lib/python3.13/getpass.py:58: UnsupportedOperation
During handling of the above exception, another exception occurred:
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x106ad6200>
capsys = <_pytest.capture.CaptureFixture object at 0x106870b90>
def test_input_password(monkeypatch, capsys) -> None:
def fake_input(prompt, stream=None):
console.file.write(prompt)
return "bar"
import getpass
monkeypatch.setattr(getpass, "getpass", fake_input)
console = Console()
> user_input = console.input(prompt="foo:", password=True)
tests/test_console.py:407:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rich/console.py:2169: in input
result = getpass("", stream=stream)
/Users/jp/.local/share/uv/python/cpython-3.13.15-macos-aarch64-none/lib/python3.13/getpass.py:61: in unix_getpass
passwd = fallback_getpass(prompt, stream)
/Users/jp/.local/share/uv/python/cpython-3.13.15-macos-aarch64-none/lib/python3.13/getpass.py:126: in fallback_getpass
return _raw_input(prompt, stream)
/Users/jp/.local/share/uv/python/cpython-3.13.15-macos-aarch64-none/lib/python3.13/getpass.py:146: in _raw_input
line = input.readline()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.DontReadFromInput object at 0x106811550>, size = -1
def read(self, size: int = -1) -> str:
> raise OSError(
"pytest: reading from stdin while output is captured! Consider using `-s`."
)
E OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/rich/lib/python3.13/site-packages/_pytest/capture.py:209: OSError
----------------------------- Captured stdout call -----------------------------
foo:
----------------------------- Captured stderr call -----------------------------
Warning: Password input may be echoed.
=============================== warnings summary ===============================
test_console.py::test_input_password
/Users/jp/.local/share/uv/python/cpython-3.13.15-macos-aarch64-none/lib/python3.13/getpass.py:61: GetPassWarning: Can not control echo on the terminal.
passwd = fallback_getpass(prompt, stream)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 42 passed, 1 warning in 0.31s