From 82479b4d6ee37da9b3e6a0d18b364bad66974ebd Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Sat, 4 Apr 2026 13:32:24 -0400 Subject: [PATCH 1/2] [Pygments] Check for missing stubs outside excluded subpackages --- stubs/Pygments/@tests/stubtest_allowlist.txt | 29 ++++++++++++++++++- stubs/Pygments/METADATA.toml | 1 - stubs/Pygments/pygments/formatter.pyi | 6 +++- .../Pygments/pygments/formatters/__init__.pyi | 26 +++++++++++++++++ stubs/Pygments/pygments/formatters/bbcode.pyi | 2 ++ stubs/Pygments/pygments/formatters/groff.pyi | 15 ++++++++++ stubs/Pygments/pygments/formatters/html.pyi | 2 ++ stubs/Pygments/pygments/formatters/img.pyi | 2 ++ stubs/Pygments/pygments/formatters/irc.pyi | 2 ++ stubs/Pygments/pygments/formatters/latex.pyi | 2 ++ stubs/Pygments/pygments/formatters/other.pyi | 2 ++ .../pygments/formatters/pangomarkup.pyi | 2 ++ stubs/Pygments/pygments/formatters/rtf.pyi | 4 +++ stubs/Pygments/pygments/formatters/svg.pyi | 2 ++ .../Pygments/pygments/formatters/terminal.pyi | 2 ++ .../pygments/formatters/terminal256.pyi | 2 ++ stubs/Pygments/pygments/lexer.pyi | 27 ++++++++++++++--- stubs/Pygments/pygments/modeline.pyi | 2 ++ stubs/Pygments/pygments/sphinxext.pyi | 1 + 19 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 stubs/Pygments/pygments/formatters/groff.pyi diff --git a/stubs/Pygments/@tests/stubtest_allowlist.txt b/stubs/Pygments/@tests/stubtest_allowlist.txt index f72c29ab5e25..5b2dfdfc458d 100644 --- a/stubs/Pygments/@tests/stubtest_allowlist.txt +++ b/stubs/Pygments/@tests/stubtest_allowlist.txt @@ -3,7 +3,34 @@ pygments.lexer.LexerMeta.__new__ pygments.style.StyleMeta.__new__ # Defined in lexer classes, intended to be used as static method, but doesn't use @staticmethod -pygments.lexer.LexerMeta.analyse_text +pygments.lexer.Lexer(Meta)?.analyse_text # Inheriting from tuple is weird pygments.token._TokenType.__init__ + +# Cannot import in stubtest (SystemExit: 2) +pygments.__main__ + +# Class attributes that are typed in the metaclass instead. See comment in stubs. +pygments.lexer.Lexer.name +pygments.lexer.Lexer.aliases +pygments.lexer.Lexer.filenames +pygments.lexer.Lexer.alias_filenames +pygments.lexer.Lexer.mimetypes +pygments.lexer.Lexer.priority +pygments.lexer.Lexer.url +pygments.lexer.Lexer.version_added +pygments.style.Style.background_color +pygments.style.Style.highlight_color +pygments.style.Style.line_number_color +pygments.style.Style.line_number_background_color +pygments.style.Style.line_number_special_color +pygments.style.Style.line_number_special_background_color +pygments.style.Style.styles +pygments.style.Style.name +pygments.style.Style.aliases +pygments.style.Style.web_style_gallery_exclude + +# Individual lexers and styles submodules are not stubbed at this time. +pygments\.lexers\.(?!get_|find_|load_|guess_).* +pygments\.styles\.(?!get_).* diff --git a/stubs/Pygments/METADATA.toml b/stubs/Pygments/METADATA.toml index 7df9c1b91951..3303aa8c712f 100644 --- a/stubs/Pygments/METADATA.toml +++ b/stubs/Pygments/METADATA.toml @@ -5,4 +5,3 @@ partial_stub = true [tool.stubtest] stubtest_dependencies = ["sphinx"] -ignore_missing_stub = true diff --git a/stubs/Pygments/pygments/formatter.pyi b/stubs/Pygments/pygments/formatter.pyi index 254f68529f33..5a9646d27c7c 100644 --- a/stubs/Pygments/pygments/formatter.pyi +++ b/stubs/Pygments/pygments/formatter.pyi @@ -1,8 +1,11 @@ +import types from _typeshed import Incomplete -from typing import Generic, TypeVar, overload +from typing import Any, Generic, TypeVar, overload _T = TypeVar("_T", str, bytes) +__all__ = ["Formatter"] + class Formatter(Generic[_T]): name: Incomplete aliases: Incomplete @@ -19,5 +22,6 @@ class Formatter(Generic[_T]): def __init__(self: Formatter[bytes], *, encoding: str, outencoding: None = None, **options) -> None: ... @overload def __init__(self: Formatter[bytes], *, encoding: None = None, outencoding: str, **options) -> None: ... + def __class_getitem__(cls, name: Any) -> types.GenericAlias: ... def get_style_defs(self, arg: str = ""): ... def format(self, tokensource, outfile): ... diff --git a/stubs/Pygments/pygments/formatters/__init__.pyi b/stubs/Pygments/pygments/formatters/__init__.pyi index f1b275f58f0f..5fdd2e310cf3 100644 --- a/stubs/Pygments/pygments/formatters/__init__.pyi +++ b/stubs/Pygments/pygments/formatters/__init__.pyi @@ -3,6 +3,7 @@ from collections.abc import Generator from ..formatter import Formatter from .bbcode import BBCodeFormatter as BBCodeFormatter +from .groff import GroffFormatter as GroffFormatter from .html import HtmlFormatter as HtmlFormatter from .img import ( BmpImageFormatter as BmpImageFormatter, @@ -19,6 +20,31 @@ from .svg import SvgFormatter as SvgFormatter from .terminal import TerminalFormatter as TerminalFormatter from .terminal256 import Terminal256Formatter as Terminal256Formatter, TerminalTrueColorFormatter as TerminalTrueColorFormatter +__all__ = [ + "get_formatter_by_name", + "get_formatter_for_filename", + "get_all_formatters", + "load_formatter_from_file", + "BBCodeFormatter", + "BmpImageFormatter", + "GifImageFormatter", + "GroffFormatter", + "HtmlFormatter", + "IRCFormatter", + "ImageFormatter", + "JpgImageFormatter", + "LatexFormatter", + "NullFormatter", + "PangoMarkupFormatter", + "RawTokenFormatter", + "RtfFormatter", + "SvgFormatter", + "Terminal256Formatter", + "TerminalFormatter", + "TerminalTrueColorFormatter", + "TestcaseFormatter", +] + def get_all_formatters() -> Generator[type[Formatter[Incomplete]]]: ... def get_formatter_by_name(_alias, **options): ... def load_formatter_from_file(filename, formattername: str = "CustomFormatter", **options): ... diff --git a/stubs/Pygments/pygments/formatters/bbcode.pyi b/stubs/Pygments/pygments/formatters/bbcode.pyi index 26758a014638..f1106e7bc2c0 100644 --- a/stubs/Pygments/pygments/formatters/bbcode.pyi +++ b/stubs/Pygments/pygments/formatters/bbcode.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["BBCodeFormatter"] + class BBCodeFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/groff.pyi b/stubs/Pygments/pygments/formatters/groff.pyi new file mode 100644 index 000000000000..59aa7b04a70a --- /dev/null +++ b/stubs/Pygments/pygments/formatters/groff.pyi @@ -0,0 +1,15 @@ +from _typeshed import SupportsWrite +from collections.abc import Iterable + +from pygments.formatter import Formatter +from pygments.token import _TokenType + +__all__ = ["GroffFormatter"] + +class GroffFormatter(Formatter): + monospaced: bool + linenos: bool + wrap: int + styles: dict[_TokenType, tuple[str, str]] + def __init__(self, **options) -> None: ... + def format_unencoded(self, tokensource: Iterable[tuple[_TokenType, str]], outfile: SupportsWrite[str]) -> None: ... diff --git a/stubs/Pygments/pygments/formatters/html.pyi b/stubs/Pygments/pygments/formatters/html.pyi index 5d5c78f4bebd..aa5347417c20 100644 --- a/stubs/Pygments/pygments/formatters/html.pyi +++ b/stubs/Pygments/pygments/formatters/html.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["HtmlFormatter"] + class HtmlFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/img.pyi b/stubs/Pygments/pygments/formatters/img.pyi index 68b30d1890bc..18b6abc8b4a9 100644 --- a/stubs/Pygments/pygments/formatters/img.pyi +++ b/stubs/Pygments/pygments/formatters/img.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["ImageFormatter", "GifImageFormatter", "JpgImageFormatter", "BmpImageFormatter"] + class PilNotAvailable(ImportError): ... class FontNotFound(Exception): ... diff --git a/stubs/Pygments/pygments/formatters/irc.pyi b/stubs/Pygments/pygments/formatters/irc.pyi index 00b45e671e70..5780fd6d1961 100644 --- a/stubs/Pygments/pygments/formatters/irc.pyi +++ b/stubs/Pygments/pygments/formatters/irc.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["IRCFormatter"] + class IRCFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/latex.pyi b/stubs/Pygments/pygments/formatters/latex.pyi index be793c6662b2..8ee188f94175 100644 --- a/stubs/Pygments/pygments/formatters/latex.pyi +++ b/stubs/Pygments/pygments/formatters/latex.pyi @@ -6,6 +6,8 @@ from pygments.lexer import Lexer _T = TypeVar("_T", str, bytes) +__all__ = ["LatexFormatter"] + class LatexFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/other.pyi b/stubs/Pygments/pygments/formatters/other.pyi index 44b16833aaf4..a17eba9b7f97 100644 --- a/stubs/Pygments/pygments/formatters/other.pyi +++ b/stubs/Pygments/pygments/formatters/other.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["NullFormatter", "RawTokenFormatter", "TestcaseFormatter"] + class NullFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/pangomarkup.pyi b/stubs/Pygments/pygments/formatters/pangomarkup.pyi index aadc1747327c..038d76f18950 100644 --- a/stubs/Pygments/pygments/formatters/pangomarkup.pyi +++ b/stubs/Pygments/pygments/formatters/pangomarkup.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["PangoMarkupFormatter"] + class PangoMarkupFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/rtf.pyi b/stubs/Pygments/pygments/formatters/rtf.pyi index da95cd0d1dfd..57eae6d738c2 100644 --- a/stubs/Pygments/pygments/formatters/rtf.pyi +++ b/stubs/Pygments/pygments/formatters/rtf.pyi @@ -5,10 +5,14 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["RtfFormatter"] + class RtfFormatter(Formatter[_T]): name: str aliases: Incomplete filenames: Incomplete fontface: Incomplete fontsize: Incomplete + @staticmethod + def hex_to_rtf_color(hex_color: str) -> str: ... def format_unencoded(self, tokensource, outfile) -> None: ... diff --git a/stubs/Pygments/pygments/formatters/svg.pyi b/stubs/Pygments/pygments/formatters/svg.pyi index 8f98d0bbf1cb..902af9fdb0db 100644 --- a/stubs/Pygments/pygments/formatters/svg.pyi +++ b/stubs/Pygments/pygments/formatters/svg.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["SvgFormatter"] + class SvgFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/terminal.pyi b/stubs/Pygments/pygments/formatters/terminal.pyi index 90ca462d6b72..8a9d681cee90 100644 --- a/stubs/Pygments/pygments/formatters/terminal.pyi +++ b/stubs/Pygments/pygments/formatters/terminal.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["TerminalFormatter"] + class TerminalFormatter(Formatter[_T]): name: str aliases: Incomplete diff --git a/stubs/Pygments/pygments/formatters/terminal256.pyi b/stubs/Pygments/pygments/formatters/terminal256.pyi index 33f17c176f78..a254a0e848d6 100644 --- a/stubs/Pygments/pygments/formatters/terminal256.pyi +++ b/stubs/Pygments/pygments/formatters/terminal256.pyi @@ -5,6 +5,8 @@ from pygments.formatter import Formatter _T = TypeVar("_T", str, bytes) +__all__ = ["Terminal256Formatter", "TerminalTrueColorFormatter"] + class EscapeSequence: fg: Incomplete bg: Incomplete diff --git a/stubs/Pygments/pygments/lexer.pyi b/stubs/Pygments/pygments/lexer.pyi index 9d760b95b206..9a2fae586e48 100644 --- a/stubs/Pygments/pygments/lexer.pyi +++ b/stubs/Pygments/pygments/lexer.pyi @@ -1,22 +1,41 @@ from _typeshed import Incomplete from collections.abc import Iterable, Iterator, Sequence -from re import RegexFlag -from typing import ClassVar +from re import Pattern, RegexFlag +from typing import ClassVar, Final from pygments.token import _TokenType from pygments.util import Future +__all__ = [ + "Lexer", + "RegexLexer", + "ExtendedRegexLexer", + "DelegatingLexer", + "LexerContext", + "include", + "inherit", + "bygroups", + "using", + "this", + "default", + "words", + "line_re", +] + +line_re: Final[Pattern[str]] + class LexerMeta(type): def __new__(cls, name, bases, d): ... def analyse_text(self, text: str) -> float: ... # actually defined in class Lexer # ClassVars of Lexer, but same situation as with StyleMeta and Style - name: str + name: str # Set to None in Lexer, but always overridden with a non-None value in subclasses. aliases: Sequence[str] # not intended mutable filenames: Sequence[str] alias_filenames: Sequence[str] mimetypes: Sequence[str] priority: float - url: str | None + url: str # Set to None in Lexer, but always overridden with a non-None value in subclasses. + version_added: str # Set to None in Lexer, but always overridden with a non-None value in subclasses. class Lexer(metaclass=LexerMeta): options: Incomplete diff --git a/stubs/Pygments/pygments/modeline.pyi b/stubs/Pygments/pygments/modeline.pyi index e13780553c31..515ff6c01c05 100644 --- a/stubs/Pygments/pygments/modeline.pyi +++ b/stubs/Pygments/pygments/modeline.pyi @@ -1 +1,3 @@ +__all__ = ["get_filetype_from_buffer"] + def get_filetype_from_buffer(buf, max_lines: int = 5): ... diff --git a/stubs/Pygments/pygments/sphinxext.pyi b/stubs/Pygments/pygments/sphinxext.pyi index cf43911fcfe6..45041edf094c 100644 --- a/stubs/Pygments/pygments/sphinxext.pyi +++ b/stubs/Pygments/pygments/sphinxext.pyi @@ -7,6 +7,7 @@ FILTERDOC: str class PygmentsDoc(Directive): filenames: set[str] + def document_lexers_overview(self) -> str: ... def document_lexers(self) -> str: ... def document_formatters(self) -> str: ... def document_filters(self) -> str: ... From 7a9b3e4684bb9491090c0b0cd900b839b8ffdc97 Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Sat, 4 Apr 2026 14:44:15 -0400 Subject: [PATCH 2/2] Fix missing typevar --- stubs/Pygments/pygments/formatters/groff.pyi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/stubs/Pygments/pygments/formatters/groff.pyi b/stubs/Pygments/pygments/formatters/groff.pyi index 59aa7b04a70a..d6b936a2dff5 100644 --- a/stubs/Pygments/pygments/formatters/groff.pyi +++ b/stubs/Pygments/pygments/formatters/groff.pyi @@ -1,12 +1,15 @@ from _typeshed import SupportsWrite from collections.abc import Iterable +from typing import TypeVar from pygments.formatter import Formatter from pygments.token import _TokenType __all__ = ["GroffFormatter"] -class GroffFormatter(Formatter): +_T = TypeVar("_T", str, bytes) + +class GroffFormatter(Formatter[_T]): monospaced: bool linenos: bool wrap: int