Skip to content

Conversation

lev-blit
Copy link
Contributor

@lev-blit lev-blit commented Oct 4, 2025

No description provided.

@lev-blit lev-blit force-pushed the feature/pygments-fill-typing branch from ec07b24 to b3485bd Compare October 4, 2025 21:05

This comment has been minimized.

@lev-blit lev-blit force-pushed the feature/pygments-fill-typing branch from c670fec to 657943f Compare October 5, 2025 19:57

This comment has been minimized.

This comment has been minimized.

@lev-blit lev-blit marked this pull request as ready for review October 5, 2025 20:53
Copy link
Collaborator

@srittau srittau left a comment

Choose a reason for hiding this comment

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

Not a full review, just a few things I have spotted.

I haven't looked the output of mypy_primer, but the amount of new typing errors in projects depending on pygments is something we need to review.

Comment on lines +108 to +117
tokendefs: (
dict[
str,
list[
tuple[str, _TokenType | Iterator[tuple[int, _TokenType, str]]]
| tuple[str, _TokenType | Iterator[tuple[int, _TokenType, str]], str]
],
]
| None
) = None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I haven't looked at this in detail, but this could be problematic. Due to the invariance of list, this will reject calls like this:

x.process_tokendef("", {"foo": [("", "")]})

In this case, the dict could be inferred to have type dict[str, list[tuple[str, str]]], but list[tuple[str, str]] is incompatible with list[tuple[str, str, str]].

Same below.

Comment on lines 37 to 38
def guess_decode_from_terminal(text: bytes, term: TextIO | Any) -> tuple[bytes, str]: ...
def terminal_encoding(term: TextIO | Any) -> str: ...
Copy link
Collaborator

Choose a reason for hiding this comment

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

Pseudo-protocols like TextIO should be avoided. In this case, we could use a protocol _HasEncoding or similar, but I think the better approach is to just use Any with a comment:

Suggested change
def guess_decode_from_terminal(text: bytes, term: TextIO | Any) -> tuple[bytes, str]: ...
def terminal_encoding(term: TextIO | Any) -> str: ...
# In the following two methods, `term` are file-like objects that optionally have an
# `encoding` attribute.
def guess_decode_from_terminal(text: bytes, term: Any) -> tuple[bytes, str]: ...
def terminal_encoding(term: Any) -> str: ...

This would be another good use case for python/typing#601.

Co-authored-by: Sebastian Rittau <sebastian.rittau@zfutura.de>

This comment has been minimized.

This comment has been minimized.

Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

pwndbg (https://github.com/pwndbg/pwndbg)
+ pwndbg/integration/binja.py: note: In member "decompile" of class "BinjaProvider":
+ pwndbg/integration/binja.py:503: error: No overload variant of "format" matches argument types "list[tuple[Any, str]]", "Terminal256Formatter[str]"  [call-overload]
+ pwndbg/integration/binja.py:503: note: Possible overload variants:
+ pwndbg/integration/binja.py:503: note:     def [_T: (str, bytes)] format(tokens: Iterator[tuple[_TokenType, str]], formatter: Formatter[_T], outfile: SupportsWrite[_T]) -> None
+ pwndbg/integration/binja.py:503: note:     def [_T: (str, bytes)] format(tokens: Iterator[tuple[_TokenType, str]], formatter: Formatter[_T], outfile: None = ...) -> _T
+ pwndbg/integration/binja.py:509: error: No overload variant of "format" matches argument types "list[tuple[Any, str]]", "Terminal256Formatter[str]"  [call-overload]
+ pwndbg/integration/binja.py:509: note: Possible overload variants:
+ pwndbg/integration/binja.py:509: note:     def [_T: (str, bytes)] format(tokens: Iterator[tuple[_TokenType, str]], formatter: Formatter[_T], outfile: SupportsWrite[_T]) -> None
+ pwndbg/integration/binja.py:509: note:     def [_T: (str, bytes)] format(tokens: Iterator[tuple[_TokenType, str]], formatter: Formatter[_T], outfile: None = ...) -> _T

sphinx (https://github.com/sphinx-doc/sphinx)
+ sphinx/highlighting.py:39: error: Unused "type: ignore" comment  [unused-ignore]
+ sphinx/highlighting.py:39:5: error: Cannot assign to a method  [method-assign]
+ sphinx/highlighting.py:39:5: note: Error code "method-assign" not covered by "type: ignore" comment
+ sphinx/highlighting.py:39:35: error: Incompatible types in assignment (expression has type "classmethod[Any, [Any], Any]", variable has type "Callable[[Any], GenericAlias]")  [assignment]
+ sphinx/highlighting.py:39:35: note: Error code "assignment" not covered by "type: ignore" comment

alectryon (https://github.com/cpitclaudel/alectryon)
+ alectryon/pygments_lexer.py:456: error: Dict entry 3 has incompatible type "str": "list[tuple[str | Any, ...]]"; expected "str": "list[tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]]] | tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]], str] | include | default]"  [dict-item]
+ alectryon/pygments_lexer.py:457: error: Dict entry 4 has incompatible type "str": "list[tuple[str | Any, ...]]"; expected "str": "list[tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]]] | tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]], str] | include | default]"  [dict-item]
+ alectryon/pygments_lexer.py:477: error: Dict entry 7 has incompatible type "str": "list[object]"; expected "str": "list[tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]]] | tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]], str] | include | default]"  [dict-item]
+ alectryon/pygments_lexer.py:490: error: Dict entry 9 has incompatible type "str": "list[object]"; expected "str": "list[tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]]] | tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]], str] | include | default]"  [dict-item]
+ alectryon/pygments_lexer.py:491: error: Dict entry 10 has incompatible type "str": "list[object]"; expected "str": "list[tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]]] | tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]], str] | include | default]"  [dict-item]
+ alectryon/pygments_lexer.py:492: error: Dict entry 11 has incompatible type "str": "list[object]"; expected "str": "list[tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]]] | tuple[str | words, _TokenType | Iterator[tuple[int, _TokenType, str]] | Callable[[Lexer, _PseudoMatch, LexerContext], Iterator[tuple[int, _TokenType, str]]], str] | include | default]"  [dict-item]

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants