Skip to content

fix(types): type hints from future python versions - #5693

Merged
henryiii merged 23 commits into
pybind:masterfrom
InvincibleRMC:fix-remaining-future-type-hints
Jun 1, 2025
Merged

fix(types): type hints from future python versions#5693
henryiii merged 23 commits into
pybind:masterfrom
InvincibleRMC:fix-remaining-future-type-hints

Conversation

@InvincibleRMC

Copy link
Copy Markdown
Contributor

Description

As shown in #5678 some types need to use typing_extensions if they don't exists yet. Similar to #5663 but, for the rest of the types.

Suggested changelog entry:

  • Add typing_extensions alternatives for all types that need them

InvincibleRMCand others added 9 commits May 25, 2025 11:28
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

@timohltimohl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Great! Those match all stubgen errors concerning new Python features I found while working on #5678.

There is one additional typing issue I found though:

template <>
structhandle_type_name<weakref> {
staticconstexprauto name = const_name("weakref");
};

weakref is not the correct type but just the module name.
I think this should be weakref.ReferenceType (docs)
Maybe we can squeeze this in here as well?

Your solution for X | Y looks good to me as well.

For testing I am not so sure about all those if sys.version_info >= (3, XX): with double asserts.
Would it maybe make sense to somehow move that into a common place as well (like in conftest.py?

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@timohltimohl mentioned this pull request May 25, 2025
4 tasks
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@InvincibleRMC

InvincibleRMC commented May 26, 2025

Copy link
Copy Markdown
ContributorAuthor

For testing I am not so sure about all those if sys.version_info >= (3, XX): with double asserts. Would it maybe make sense to somehow move that into a common place as well (like in conftest.py?

I forgot that mypy can use future python features in .pyi files would it better/simpler to just switch everything over to X | Y in the test cases?

pre-commit-ciBotand others added 2 commits May 26, 2025 21:04
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@timohl

Copy link
Copy Markdown
Contributor

For testing I am not so sure about all those if sys.version_info >= (3, XX): with double asserts. Would it maybe make sense to somehow move that into a common place as well (like in conftest.py?

I forgot that mypy can use future python features in .pyi files would it better/simpler to just switch everything over to X | Y in the test cases?

That would make the tests a lot simpler, so I think this is a good idea.
With across_version_type_hint_checker everything should look cleaner.

How is the test output when the assert inside across_version_type_hint_checker fails?
Is it still clear where the error occurs and what the context is (just curious how pytest handles asserts in helper functions)?

I can have a deeper look tomorrow evening on your latest changes.

Comment threadtests/test_opaque_types.py Outdated
from __future__ import annotations

import pytest
from conftest import across_version_type_hint_checker

@henryiiihenryiiiMay 27, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please, never import from conftest.py. You can put fixtures, etc. there, but don't import from it. It causes all sorts of issues (such as the issue holding up cibuildwheel 3.0 in numpy right now!); it's not meant to be an importable module for users. We sadly have one case (tests/test_docs_advanced_cast_custom.py), but I'd like to get rid of that, not add more. Edit: it's only at type check time!

Instead of adding a test/utils directory just for this, and requiring PyTest 7+, this can be wrapped in a fixture for now.

Since we do have one case of importing from conftest, I'm also okay to leave this in for now and add the test utils in a followup later, as anything broken by it will already have workarounds.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does this also reduce the quality of assertion rewriting?

@henryiiihenryiiiMay 27, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

FYI, wrapping it in a fixture could look like:

@pytest.fixturedefbackport_typehints() ->Callable[[str], str]:
d= {}
ifsys.version_info< (3, 13):
d["typing.TypeIs"] ="typing_extensions.TypeIs"d["types.CapsuleType"] ="typing_extensions.CapsuleType"ifsys.version_info< (3, 12):
d["collections.abc.Buffer"] ="typing_extensions.Buffer"ifsys.version_info< (3, 11):
d["typing.Never"] ="typing_extensions.Never"ifsys.version_info< (3, 10):
d["typing.TypeGuard"] ="typing_extensions.TypeGuard"defbackport(text: str) ->str:
forold, newind.items():
text=text.replace(old, new)
returntextreturnbackport

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please, never import from conftest.py. You can put fixtures, etc. there, but don't import from it. It causes all sorts of issues (such as the issue holding up cibuildwheel 3.0 in numpy right now!); it's not meant to be an importable module for users. We sadly have one case (tests/test_docs_advanced_cast_custom.py), but I'd like to get rid of that, not add more. Edit: it's only at type check time!

Just to clarify and to learn from it (since I added that conftest.py import in tests/test_docs_advanced_cast_custom.py):
Would you also discourage from importing conftest.py while using if TYPE_CHECKING?
Generally, I like having type hints for function arguments for better code readability and navigation.
Vscode/Pylance is capable of matching test arguments to fixtures and show gray type hints without manual type annotations, so I could see not having those in tests.

@henryiiihenryiii changed the title Fix type hints from future python versionsfix(types): type hints from future python versionsMay 27, 2025

@timohltimohl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two minor comments, otherwise this looks good to me.

Comment threadtests/conftest.py Outdated
Comment threadinclude/pybind11/stl.h Outdated
InvincibleRMCand others added 5 commits May 27, 2025 15:59
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@henryiii
henryiii requested a review from CopilotMay 31, 2025 19:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR modernizes type hint generation by switching from typing.Union/Optional syntax to PEP 604 (‘|’) across C++ headers and Python tests, and adds a pytest fixture to backport new hints on older Python versions.

  • Replace legacy typing.Union[...]/typing.Optional[...] strings with the | operator in C++ io_name and handle_type_name.
  • Introduce backport_typehints fixture in conftest.py to swap typing_extensions hints to built-in typing on older Pythons.
  • Update test assertions throughout tests/ to expect the new union-syntax and use backport_typehints where needed.

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
tests/test_stl.pyAdd docstring checks for reference-sensitive and filesystem types
tests/test_pytypes.pyUpdate expected doc outputs to use `
tests/test_pytypes.cppChange io_name for RealNumber to `"float
tests/test_opaque_types.pyAdd backport_typehints fixture to pointer error message tests
tests/test_buffers.pySimplify buffer docstring test and use new hint syntax
tests/conftest.pyIntroduce backport_typehints fixture for hint backporting
include/pybind11/typing.hUse union_concat and `
include/pybind11/stl/filesystem.hSwitch filesystem caster to `os.PathLike
include/pybind11/stl.hSimplify optional_caster/variant_caster to pipe syntax
include/pybind11/detail/descr.hImplement union_concat and `operator
include/pybind11/detail/common.hAdd macros for typing_extensions vs. built-in hints
include/pybind11/cast.hUpdate CapsuleType and anyset names to use compatibility macros

Comment threadtests/test_buffers.py
@henryiii
henryiii merged commit c2b32b1 into pybind:masterJun 1, 2025
@github-actionsgithub-actionsBot added the needs changelog Possibly needs a changelog entry label Jun 1, 2025
@henryiiihenryiii removed the needs changelog Possibly needs a changelog entry label Jun 19, 2025
Sign up for freeto 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.

4 participants

@InvincibleRMC@timohl@henryiii