Skip to content

gh-144384: Lazily import _colorize#149318

Open
hugovk wants to merge 7 commits intopython:mainfrom
hugovk:3.15-lazy-_colorize
Open

gh-144384: Lazily import _colorize#149318
hugovk wants to merge 7 commits intopython:mainfrom
hugovk:3.15-lazy-_colorize

Conversation

@hugovk
Copy link
Copy Markdown
Member

@hugovk hugovk commented May 3, 2026

Lazily import _colorize to avoid slow construction/import when not needed.

The easily testable:

Before After
difflib: 10ms 2ms (80% faster)
image image
doctest: 48ms 40ms (17% faster)
image image
json.tool: 13ms 6ms (54% faster)
image image
pdb: 43ms 37ms (14% faster)
image image
traceback: 15ms 8ms (47% faster)
image image
unittest: 20ms 14ms (30% faster)
image image

Some indirect improvements:

Before After
asyncio: 47ms 27ms (43% faster)
image image
logging: 17ms 10ms (41% faster)
image image

traceback needs some extra handling: add a shutdown theme, so if it attempts to reify _colorize during shutdown when the import machinery is no longer around, it has a no-op fallback.

Also add ensure_lazy_imports tests.

@hugovk hugovk requested a review from berkerpeksag as a code owner May 3, 2026 14:32
@hugovk hugovk added the performance Performance or resource usage label May 3, 2026
@hugovk hugovk added the stdlib Standard Library Python modules in the Lib/ directory label May 3, 2026
@hugovk hugovk requested review from ambv and gaogaotiantian as code owners May 3, 2026 14:32
Copy link
Copy Markdown
Member

@picnixz picnixz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a convention for lazy imports

Comment thread Lib/_pyrepl/fancycompleter.py Outdated
# All Rights Reserved
"""Colorful tab completion for Python prompt"""
from _colorize import ANSIColors, get_colors, get_theme
lazy from _colorize import ANSIColors, get_colors, get_theme
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a blank line before the lazy import please to improve readability? You could also move the lazy from after the import list as you did for other modules.

Comment thread Lib/traceback.py
Comment thread Lib/traceback.py
Comment on lines +37 to +44
def _safe_get_theme(*, force_color=False, force_no_color=False):
try:
return _colorize.get_theme(
force_color=force_color, force_no_color=force_no_color
)
except ImportError:
return _shutdown_theme

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stupid question here, but can't we just use a local import then instead of a lazy one? or would we still have an issue with real imports?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, test_print_traceback_at_exit fails with a local import. Things are very much in shutdown there!

Copy link
Copy Markdown
Member Author

@hugovk hugovk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a convention for lazy imports

Yes, given we don't have a convention, and the SC left it the details to linters and auto-formatters, let's generally follow the Ruff/isort convention:

import json
import os
import subprocess
from collections import defaultdict
from pathlib import Path
from typing import Final
lazy import ast
lazy import shutil
lazy from dataclasses import dataclass

Comment thread Lib/traceback.py
Comment thread Lib/traceback.py
Comment on lines +37 to +44
def _safe_get_theme(*, force_color=False, force_no_color=False):
try:
return _colorize.get_theme(
force_color=force_color, force_no_color=force_no_color
)
except ImportError:
return _shutdown_theme

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, test_print_traceback_at_exit fails with a local import. Things are very much in shutdown there!

Comment thread Lib/traceback.py
lazy import _colorize


class _ShutdownTheme:
Copy link
Copy Markdown
Member

@picnixz picnixz May 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shutdown logic could be moved after the _missing_stdlib_info actually line because _missing_stdlib_info is still imported (so probably after the __all__). Or is it also because we want to have those objects as soon as possible at interpreter's finalization?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep it can move, I put it below __all__.

@StanFromIreland
Copy link
Copy Markdown
Member

Seeing #149321, I think this should wait till that is somewhat figured out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review performance Performance or resource usage stdlib Standard Library Python modules in the Lib/ directory

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants