Skip to content

[docutils] Add missing stubs for writers dir #14223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 21, 2025

Conversation

donBarbos
Copy link
Contributor

No description provided.

@donBarbos donBarbos marked this pull request as ready for review June 5, 2025 16:18
@donBarbos donBarbos changed the title [docutils]: Add missing stubs for writers dir [docutils] Add missing stubs for writers dir Jun 5, 2025

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

@srittau
Copy link
Collaborator

srittau commented Jul 11, 2025

See my comment about visit methods in #14234: We should probably just add them to NodeVisitor with standard types and leave them alone in sub-classes (unless those sub-classes do anything fancy with them).

@donBarbos
Copy link
Contributor Author

See my comment about visit methods in #14234: We should probably just add them to NodeVisitor with standard types and leave them alone in sub-classes (unless those sub-classes do anything fancy with them).

Judging by mypy primer output, there is only one mismatched override visit method - visit_comment, and there is a comment about it (sphinx source code comment)

Copy link
Contributor

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

sphinx (https://github.com/sphinx-doc/sphinx)
+ sphinx/writers/html5.py:44: error: Unused "type: ignore" comment  [unused-ignore]
+ sphinx/writers/html5.py: note: In member "visit_reference" of class "HTML5Translator":
+ sphinx/writers/html5.py:350:57: error: Argument 4 to "starttag" of "HTMLTranslator" has incompatible type "**dict[str, str]"; expected "bool"  [arg-type]
+ sphinx/writers/html5.py: note: In member "visit_comment" of class "HTML5Translator":
+ sphinx/writers/html5.py:364:5: error: Signature of "visit_comment" incompatible with supertype "HTMLTranslator"  [override]
+ sphinx/writers/html5.py:364:5: note:      Superclass:
+ sphinx/writers/html5.py:364:5: note:          def visit_comment(self, node: comment, sub: Callable[[str, str], str] = ...) -> None
+ sphinx/writers/html5.py:364:5: note:      Subclass:
+ sphinx/writers/html5.py:364:5: note:          def visit_comment(self, node: Element) -> None
+ sphinx/writers/html5.py: note: In member "visit_admonition" of class "HTML5Translator":
+ sphinx/writers/html5.py:376:73: error: Argument 4 to "starttag" of "HTMLTranslator" has incompatible type "**dict[str, str]"; expected "bool"  [arg-type]
+ sphinx/writers/html5.py: note: In member "visit_download_reference" of class "HTML5Translator":
+ sphinx/writers/html5.py:727:61: error: Argument 4 to "starttag" of "HTMLTranslator" has incompatible type "**dict[str, str]"; expected "bool"  [arg-type]
+ sphinx/writers/html5.py:734:61: error: Argument 4 to "starttag" of "HTMLTranslator" has incompatible type "**dict[str, str]"; expected "bool"  [arg-type]
+ sphinx/writers/html5.py: note: In member "visit_abbreviation" of class "HTML5Translator":
+ sphinx/writers/html5.py:911:60: error: Argument 4 to "starttag" of "HTMLTranslator" has incompatible type "**dict[str, str]"; expected "bool"  [arg-type]
+ sphinx/writers/html5.py: note: In member "visit_table" of class "HTML5Translator":
+ sphinx/writers/html5.py:936:71: error: Argument 4 to "starttag" of "HTMLTranslator" has incompatible type "**dict[str, str]"; expected "bool"  [arg-type]
+ sphinx/writers/html.py:23: error: Unused "type: ignore" comment  [unused-ignore]
+ sphinx/writers/html.py: note: In member "translate" of class "HTMLWriter":
+ sphinx/writers/html.py:36:9: error: Item "None" of "document | None" has no attribute "walkabout"  [union-attr]
+ sphinx/writers/xml.py:15: error: Unused "type: ignore" comment  [unused-ignore]
+ sphinx/writers/xml.py: note: In member "translate" of class "XMLWriter":
+ sphinx/writers/xml.py:24:9: error: Item "None" of "document | None" has no attribute "settings"  [union-attr]
+ sphinx/writers/xml.py:27:9: error: Item "None" of "document | None" has no attribute "settings"  [union-attr]
+ sphinx/writers/xml.py:28:9: error: Item "None" of "document | None" has no attribute "settings"  [union-attr]
+ sphinx/writers/xml.py:32:9: error: Incompatible types in assignment (expression has type "NodeVisitor", variable has type "XMLTranslator")  [assignment]
+ sphinx/writers/xml.py:33:9: error: Item "None" of "document | None" has no attribute "walkabout"  [union-attr]
+ sphinx/writers/xml.py: note: At top level:
+ sphinx/writers/xml.py:37: error: Unused "type: ignore" comment  [unused-ignore]
+ sphinx/writers/xml.py: note: In member "translate" of class "PseudoXMLWriter":
+ sphinx/writers/xml.py:52:23: error: Item "None" of "document | None" has no attribute "pformat"  [union-attr]
+ sphinx/writers/manpage.py:28: error: Unused "type: ignore" comment  [unused-ignore]
+ sphinx/writers/manpage.py: note: In member "translate" of class "ManualPageWriter":
+ sphinx/writers/manpage.py:34:43: error: Argument 1 to "NestedInlineTransform" has incompatible type "document | None"; expected "document"  [arg-type]
+ sphinx/writers/manpage.py:38:9: error: Item "None" of "document | None" has no attribute "walkabout"  [union-attr]
+ sphinx/builders/xml.py: note: In member "_translate" of class "XMLBuilder":
+ sphinx/builders/xml.py:90:34: error: Incompatible types in assignment (expression has type "NodeVisitor", variable has type "XMLTranslator")  [assignment]

@srittau
Copy link
Collaborator

srittau commented Jul 21, 2025

sphinx/writers/html5.py:350:57: error: Argument 4 to "starttag" of "HTMLTranslator" has incompatible type "**dict[str, str]"; expected "bool" [arg-type]

This is a weird semi-false positive. starttag – matching the implementation – is now:

def starttag(self, node: nodes.Element, tagname: str, suffix: str = "\n", empty: bool = False, **attributes) -> str: ...

This is called with self.starttag(node, 'a', '', **atts), where atts is dict[str, str]. I assume that mypy is not liking that in theory atts could contain empty: "foo", which would conflict with starttag. I don't think there's much we can do, though.

Overall the primer hits all seem in the category "nothing we can do about".

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.

LGTM

@srittau srittau merged commit d57b2fb into python:main Jul 21, 2025
49 checks passed
@donBarbos
Copy link
Contributor Author

This is a weird semi-false positive. starttag – matching the implementation – is now:

I noticed this too and wrote an example when mypy complains:

from typing import Any

def test(v: bool = True, **kwargs: Any) -> None:
    print(f"{v=}")
    print(f"{kwargs=}")

if __name__ == "__main__":
    kwargs = {"a": 4, "b": "a", "c": None}
    test(**kwargs)

And result:

~ uv run main.py
v=True
kwargs={'a': 4, 'b': 'a', 'c': None}
~ uv run mypy main.py
main.py:9: error: Argument 1 to "test" has incompatible type "**dict[str, object]"; expected "bool"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

But the interesting thing is that if you explicitly specify that kwargs is a dict (at least kwargs: dict = ...), then mypy won't complain

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