Lazily import pygments in TerminalWriter - #14948
Closed
yoshi-taka wants to merge 1 commit into
Closed
Conversation
pygments is no longer imported at module load of _pytest._io.terminalwriter. It is imported only when source is actually syntax-highlighted, avoiding the import on runs without markup (e.g. most CI executions) and reducing startup time. Considerations / risk analysis: - The function return annotations (Lexer, TerminalFormatter) are only needed for type checkers; the module uses `from __future__ import annotations`, so they are never evaluated at runtime. They are imported under TYPE_CHECKING. - Highlighting remains gated by `hasmarkup` / `code_highlight`, so behavior is unchanged: runs without color output (typical CI) never import pygments, while color runs import it once on first traceback, as before. - No public API is changed. All pygments imports were moved into the methods that use them. Because `pygments` is no longer imported at module level, the previously qualified references (`pygments.util.ClassNotFound`, `pygments.util.OptionError`, `pygments.highlight`) could only be reached via the `pygments` module object, which would mean importing the whole `pygments` package inside each of those methods — the very thing this change is trying to avoid. So the names are imported directly (e.g. `from pygments.util import ClassNotFound`, `from pygments import highlight`) and used unqualified. This is a naming-only change — the caught exceptions and the highlighted output are identical. - A regression test asserts pygments is not imported when the module is loaded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
pygmentsis no longer imported at module load of_pytest/_io/terminalwriter.py.It is imported lazily, only when source is actually syntax-highlighted (e.g. when
rendering a traceback with color output). This avoids importing the relatively heavy
pygmentspackage on runs that don't need it — notably runs without markup, such asmost CI executions — slightly reducing pytest's startup time.
Risk analysis / considerations
Lexer,TerminalFormatter) are only needed fortype checkers; the module already uses
from __future__ import annotations, so theyare never evaluated at runtime. They are imported under
TYPE_CHECKING.hasmarkup/code_highlight, so behavior isunchanged: runs without color output (typical CI) never import
pygments, whilecolor runs import it once on first traceback, as before.
pygmentsimports were moved into the methods thatuse them. Because
pygmentsis no longer imported at module level, the previouslyqualified references (
pygments.util.ClassNotFound,pygments.util.OptionError,pygments.highlight) could only be reached via thepygmentsmodule object, whichwould mean importing the whole
pygmentspackage inside each of those methods — thevery thing this change is trying to avoid. So the names are imported directly (e.g.
from pygments.util import ClassNotFound,from pygments import highlight) and usedunqualified. This is a naming-only change — the caught exceptions and the highlighted
output are identical.
pygmentsis not imported when the module is loaded.Notes on Python versions
lazyimportkeyword (PEP 810, Final, shipped in 3.15): it is a 3.15-only soft keyword and would
be a
SyntaxErroron older interpreters.__lazy_modules__module-level opt-in that is a no-op before3.15, but moving the imports into the functions that use them is simpler, works
uniformly across all supported versions, and matches the approach already used in this
codebase (e.g.
unittestindebugging).PYTHON_LAZY_IMPORTS=allmode (alreadyexercised by
testing/test_assertrewrite.py): a function-local import resolves atfirst use regardless of the global lazy-import setting.
Checklist
(added
test_terminalwriter_import_does_not_import_pygments)changelog/14948.improvement.rst)AUTHORSin alphabetical order — skipped (minor/internal change)