From 337a11ee7cf6eeac49f1da514d89673c68738a5a Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 12 Sep 2025 12:57:09 +0100 Subject: [PATCH 01/10] Add basic support for PEP 695 type parameters in functions (#17) * Add support for basic PEP 695 type parameters in functions * Add tests * Reorder imports * Reformat * Reformat * Add stubs * Add exported names * Do not add typevar if name is a parameter If the name was given a a type parameter a TypeVar variable is not needed. --- pybind11_stubgen/parser/interface.py | 11 +++- pybind11_stubgen/parser/mixins/fix.py | 25 ++++++++- pybind11_stubgen/parser/mixins/parse.py | 52 ++++++++++++++++--- pybind11_stubgen/printer.py | 17 ++++-- pybind11_stubgen/structs.py | 1 + .../bindings/src/modules/functions.cpp | 30 +++++++++++ .../demo/_bindings/functions.pyi | 14 +++++ .../demo/_bindings/functions.pyi | 14 +++++ .../demo/_bindings/functions.pyi | 14 +++++ .../demo/_bindings/functions.pyi | 14 +++++ .../demo/_bindings/functions.pyi | 14 +++++ .../demo/_bindings/functions.pyi | 14 +++++ .../demo/_bindings/functions.pyi | 14 +++++ 13 files changed, 218 insertions(+), 16 deletions(-) diff --git a/pybind11_stubgen/parser/interface.py b/pybind11_stubgen/parser/interface.py index 86a4f882..ecd49c97 100644 --- a/pybind11_stubgen/parser/interface.py +++ b/pybind11_stubgen/parser/interface.py @@ -2,7 +2,7 @@ import abc import types -from typing import Any +from typing import Any, Callable, TypeVar from pybind11_stubgen.parser.errors import ParserError from pybind11_stubgen.structs import ( @@ -23,6 +23,8 @@ Value, ) +T = TypeVar("T") + class IParser(abc.ABC): @abc.abstractmethod @@ -80,6 +82,13 @@ def handle_type(self, type_: type) -> QualifiedName: ... @abc.abstractmethod def handle_value(self, value: Any) -> Value: ... + def call_with_local_types(self, parameters: list[str], func: Callable[[], T]) -> T: + """ + PEP 695 added template syntax to classes and functions. + This will call the function with these additional local types. + """ + ... + @abc.abstractmethod def parse_args_str(self, args_str: str) -> list[Argument]: ... diff --git a/pybind11_stubgen/parser/mixins/fix.py b/pybind11_stubgen/parser/mixins/fix.py index 87898906..648d7d73 100644 --- a/pybind11_stubgen/parser/mixins/fix.py +++ b/pybind11_stubgen/parser/mixins/fix.py @@ -7,7 +7,7 @@ import sys import types from logging import getLogger -from typing import Any, Sequence +from typing import Any, Callable, Sequence, TypeVar from pybind11_stubgen.parser.errors import ( InvalidExpressionError, @@ -38,6 +38,8 @@ logger = getLogger("pybind11_stubgen") +T = TypeVar("T") + class RemoveSelfAnnotation(IParser): @@ -88,6 +90,7 @@ def __init__(self): self.__extra_imports: set[Import] = set() self.__current_module: types.ModuleType | None = None self.__current_class: type | None = None + self.__local_types: set[str] = set() def handle_alias(self, path: QualifiedName, origin: Any) -> Alias | None: result = super().handle_alias(path, origin) @@ -144,6 +147,13 @@ def handle_value(self, value: Any) -> Value: self._add_import(QualifiedName.from_str(result.repr)) return result + def call_with_local_types(self, parameters: list[str], func: Callable[[], T]) -> T: + original_local_types = self.__local_types.copy() + self.__local_types.update(parameters) + result = super().call_with_local_types(parameters, func) + self.__local_types = original_local_types + return result + def parse_annotation_str( self, annotation_str: str ) -> ResolvedType | InvalidExpression | Value: @@ -155,7 +165,7 @@ def parse_annotation_str( def _add_import(self, name: QualifiedName) -> None: if len(name) == 0: return - if len(name) == 1 and len(name[0]) == 0: + if len(name) == 1 and (len(name[0]) == 0 or name[0] in self.__local_types): return if hasattr(builtins, name[0]): return @@ -636,6 +646,7 @@ class FixNumpyArrayDimTypeVar(IParser): numpy_primitive_types = FixNumpyArrayDimAnnotation.numpy_primitive_types __DIM_VARS: set[str] = set() + __local_types: set[str] = set() def handle_module( self, path: QualifiedName, module: types.ModuleType @@ -662,6 +673,13 @@ def handle_module( return result + def call_with_local_types(self, parameters: list[str], func: Callable[[], T]) -> T: + original_local_types = self.__local_types.copy() + self.__local_types.update(parameters) + result = super().call_with_local_types(parameters, func) + self.__local_types = original_local_types + return result + def parse_annotation_str( self, annotation_str: str ) -> ResolvedType | InvalidExpression | Value: @@ -675,6 +693,9 @@ def parse_annotation_str( if not isinstance(result, ResolvedType): return result + if len(result.name) == 1 and result.name[0] in self.__local_types: + return result + # handle unqualified, single-letter annotation as a TypeVar if len(result.name) == 1 and len(result.name[0]) == 1: result.name = QualifiedName.from_str(result.name[0].upper()) diff --git a/pybind11_stubgen/parser/mixins/parse.py b/pybind11_stubgen/parser/mixins/parse.py index e88fe352..a16d337c 100644 --- a/pybind11_stubgen/parser/mixins/parse.py +++ b/pybind11_stubgen/parser/mixins/parse.py @@ -4,7 +4,7 @@ import inspect import re import types -from typing import Any +from typing import Any, Callable, TypeVar from pybind11_stubgen.parser.errors import ( InvalidExpressionError, @@ -40,6 +40,8 @@ Argument(name=Identifier("kwargs"), kw_variadic=True), ] +T = TypeVar("T") + class ParserDispatchMixin(IParser): def handle_class(self, path: QualifiedName, class_: type) -> Class | None: @@ -384,6 +386,9 @@ def handle_type(self, type_: type) -> QualifiedName: ) ) + def call_with_local_types(self, parameters: list[str], func: Callable[[], T]) -> T: + return func() + def parse_value_str(self, value: str) -> Value | InvalidExpression: return self._parse_expression_str(value) @@ -624,7 +629,8 @@ def parse_function_docstring( return [] top_signature_regex = re.compile( - rf"^{func_name}\((?P.*)\)\s*(->\s*(?P.+))?$" + rf"^{func_name}(\[(?P[\w\s,]*)])?" + rf"\((?P.*)\)\s*(->\s*(?P.+))?$" ) match = top_signature_regex.match(doc_lines[0]) @@ -632,24 +638,39 @@ def parse_function_docstring( return [] if len(doc_lines) < 2 or doc_lines[1] != "Overloaded function.": + # TODO: Update to support more complex formats. + # This only supports bare type parameters. + type_vars: list[str] = list( + filter( + bool, map(str.strip, (match.group("type_vars") or "").split(",")) + ) + ) + args = self.call_with_local_types( + type_vars, lambda: self.parse_args_str(match.group("args")) + ) + returns_str = match.group("returns") if returns_str is not None: - returns = self.parse_annotation_str(returns_str) + returns = self.call_with_local_types( + type_vars, lambda: self.parse_annotation_str(returns_str) + ) else: returns = None return [ Function( name=func_name, - args=self.parse_args_str(match.group("args")), + args=args, doc=self._strip_empty_lines(doc_lines[1:]), returns=returns, + type_vars=type_vars, ) ] overload_signature_regex = re.compile( - rf"^(\s*(?P\d+).\s*)" - rf"{func_name}\((?P.*)\)\s*->\s*(?P.+)$" + rf"^(\s*(?P\d+)\.\s*)" + rf"{func_name}(\[(?P[\w\s,]*)])?" + rf"\((?P.*)\)\s*->\s*(?P.+)$" ) doc_start = 0 @@ -663,16 +684,31 @@ def parse_function_docstring( continue overloads[-1].doc = self._strip_empty_lines(doc_lines[doc_start:i]) doc_start = i + 1 + # TODO: Update to support more complex formats. + # This only supports bare type parameters. + type_vars: list[str] = list( + filter( + bool, + map(str.strip, (match.group("type_vars") or "").split(",")), + ) + ) + args = self.call_with_local_types( + type_vars, lambda: self.parse_args_str(match.group("args")) + ) + returns = self.call_with_local_types( + type_vars, lambda: self.parse_annotation_str(match.group("returns")) + ) overloads.append( Function( name=func_name, - args=self.parse_args_str(match.group("args")), - returns=self.parse_annotation_str(match.group("returns")), + args=args, + returns=returns, doc=None, decorators=[ # use `parse_annotation_str()` to trigger typing import Decorator(str(self.parse_annotation_str("typing.overload"))) ], + type_vars=type_vars, ) ) diff --git a/pybind11_stubgen/printer.py b/pybind11_stubgen/printer.py index 5412ba91..dfe802d0 100644 --- a/pybind11_stubgen/printer.py +++ b/pybind11_stubgen/printer.py @@ -151,11 +151,18 @@ def print_function(self, func: Function) -> list[str]: args.append(self.print_argument(arg)) if len(args) > 0 and args[0] == "/": args = args[1:] - signature = [ - f"def {func.name}(", - ", ".join(args), - ")", - ] + signature = [f"def {func.name}"] + + if func.type_vars: + signature.extend(["[", ", ".join(func.type_vars), "]"]) + + signature.extend( + [ + "(", + ", ".join(args), + ")", + ] + ) if func.returns is not None: signature.append(f" -> {self.print_annotation(func.returns)}") diff --git a/pybind11_stubgen/structs.py b/pybind11_stubgen/structs.py index 0026d2f5..79ad65c6 100644 --- a/pybind11_stubgen/structs.py +++ b/pybind11_stubgen/structs.py @@ -142,6 +142,7 @@ class Function: returns: Annotation | None = field_(default=None) doc: Docstring | None = field_(default=None) decorators: list[Decorator] = field_(default_factory=list) + type_vars: list[str] = field_(default_factory=list) def __str__(self): return ( diff --git a/tests/py-demo/bindings/src/modules/functions.cpp b/tests/py-demo/bindings/src/modules/functions.cpp index 15488da6..c122dc70 100644 --- a/tests/py-demo/bindings/src/modules/functions.cpp +++ b/tests/py-demo/bindings/src/modules/functions.cpp @@ -101,4 +101,34 @@ void bind_functions_module(py::module &&m) { m.def("default_custom_arg", [](Foo &foo) {}, py::arg_v("foo", Foo(5), "Foo(5)")); m.def("pass_callback", [](std::function &callback) { return Foo(13); }); m.def("nested_types", [](std::variant, Foo> arg){ return arg; }); + +#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12) + py::options options; + options.disable_function_signatures(); + m.def( + "passthrough1", + [](py::object obj) { return obj; }, + py::doc("passthrough1[T](obj: T) -> T\n")); + m.def( + "passthrough2", + [](py::object obj) { return obj; }, + py::doc( + "passthrough2(*args, **kwargs)\n" + "Overloaded function.\n" + "1. passthrough2() -> None\n" + "2. passthrough2[T](obj: T) -> T\n"), + py::arg("obj") = py::none()); + m.def( + "passthrough3", + [](py::object obj1, py::object obj2) { return py::make_tuple(obj1, obj2); }, + py::doc( + "passthrough3(*args, **kwargs)\n" + "Overloaded function.\n" + "1. passthrough3() -> tuple[None, None]\n" + "2. passthrough3[T](obj: T) -> tuple[T, None]\n" + "3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]\n"), + py::arg("obj1") = py::none(), + py::arg("obj2") = py::none()); + options.enable_function_signatures(); +#endif } diff --git a/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 316386c8..f5bf1819 100644 --- a/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -20,6 +20,9 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -54,5 +57,16 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1[T](obj: T) -> T: ... +@typing.overload +def passthrough2() -> None: ... +@typing.overload +def passthrough2[T](obj: T) -> T: ... +@typing.overload +def passthrough3() -> tuple[None, None]: ... +@typing.overload +def passthrough3[T](obj: T) -> tuple[T, None]: ... +@typing.overload +def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 72ab6498..2ae96f1a 100644 --- a/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -21,6 +21,9 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -56,5 +59,16 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1[T](obj: T) -> T: ... +@typing.overload +def passthrough2() -> None: ... +@typing.overload +def passthrough2[T](obj: T) -> T: ... +@typing.overload +def passthrough3() -> tuple[None, None]: ... +@typing.overload +def passthrough3[T](obj: T) -> tuple[T, None]: ... +@typing.overload +def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi index 72ab6498..2ae96f1a 100644 --- a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -21,6 +21,9 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -56,5 +59,16 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1[T](obj: T) -> T: ... +@typing.overload +def passthrough2() -> None: ... +@typing.overload +def passthrough2[T](obj: T) -> T: ... +@typing.overload +def passthrough3() -> tuple[None, None]: ... +@typing.overload +def passthrough3[T](obj: T) -> tuple[T, None]: ... +@typing.overload +def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 72ab6498..2ae96f1a 100644 --- a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -21,6 +21,9 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -56,5 +59,16 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1[T](obj: T) -> T: ... +@typing.overload +def passthrough2() -> None: ... +@typing.overload +def passthrough2[T](obj: T) -> T: ... +@typing.overload +def passthrough3() -> tuple[None, None]: ... +@typing.overload +def passthrough3[T](obj: T) -> tuple[T, None]: ... +@typing.overload +def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 2f467b68..4f239aa6 100644 --- a/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -19,6 +19,9 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -52,5 +55,16 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1[T](obj: T) -> T: ... +@typing.overload +def passthrough2() -> None: ... +@typing.overload +def passthrough2[T](obj: T) -> T: ... +@typing.overload +def passthrough3() -> tuple[None, None]: ... +@typing.overload +def passthrough3[T](obj: T) -> tuple[T, None]: ... +@typing.overload +def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi index f24c3270..e6a83345 100644 --- a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -22,6 +22,9 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -63,6 +66,17 @@ def mul(p: typing.SupportsFloat, q: typing.SupportsFloat) -> float: def nested_types(arg0: collections.abc.Sequence[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: collections.abc.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1[T](obj: T) -> T: ... +@typing.overload +def passthrough2() -> None: ... +@typing.overload +def passthrough2[T](obj: T) -> T: ... +@typing.overload +def passthrough3() -> tuple[None, None]: ... +@typing.overload +def passthrough3[T](obj: T) -> tuple[T, None]: ... +@typing.overload +def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index f24c3270..e6a83345 100644 --- a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -22,6 +22,9 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -63,6 +66,17 @@ def mul(p: typing.SupportsFloat, q: typing.SupportsFloat) -> float: def nested_types(arg0: collections.abc.Sequence[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: collections.abc.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1[T](obj: T) -> T: ... +@typing.overload +def passthrough2() -> None: ... +@typing.overload +def passthrough2[T](obj: T) -> T: ... +@typing.overload +def passthrough3() -> tuple[None, None]: ... +@typing.overload +def passthrough3[T](obj: T) -> tuple[T, None]: ... +@typing.overload +def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... From 8fc6dbdc6ef3f648402671da8c40e4f0c75f227e Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 09:06:01 +0000 Subject: [PATCH 02/10] Disable PEP 695 support prior to 3.12 --- pybind11_stubgen/parser/mixins/parse.py | 14 +++++++++----- tests/py-demo/bindings/src/modules/functions.cpp | 10 ++++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pybind11_stubgen/parser/mixins/parse.py b/pybind11_stubgen/parser/mixins/parse.py index a16d337c..db044739 100644 --- a/pybind11_stubgen/parser/mixins/parse.py +++ b/pybind11_stubgen/parser/mixins/parse.py @@ -5,6 +5,7 @@ import re import types from typing import Any, Callable, TypeVar +import sys from pybind11_stubgen.parser.errors import ( InvalidExpressionError, @@ -628,9 +629,12 @@ def parse_function_docstring( if len(doc_lines) == 0: return [] + type_var_pattern = re.compile(r"(\[(?P[\w\s,]*)])?") + top_signature_regex = re.compile( - rf"^{func_name}(\[(?P[\w\s,]*)])?" - rf"\((?P.*)\)\s*(->\s*(?P.+))?$" + rf"^{func_name}" + + type_var_pattern.pattern * ((1, 12) <= sys.version_info) + + r"\((?P.*)\)\s*(->\s*(?P.+))?$" ) match = top_signature_regex.match(doc_lines[0]) @@ -668,9 +672,9 @@ def parse_function_docstring( ] overload_signature_regex = re.compile( - rf"^(\s*(?P\d+)\.\s*)" - rf"{func_name}(\[(?P[\w\s,]*)])?" - rf"\((?P.*)\)\s*->\s*(?P.+)$" + rf"^(\s*(?P\d+)\.\s*){func_name}" + + type_var_pattern.pattern * ((1, 12) <= sys.version_info) + + r"\((?P.*)\)\s*->\s*(?P.+)$" ) doc_start = 0 diff --git a/tests/py-demo/bindings/src/modules/functions.cpp b/tests/py-demo/bindings/src/modules/functions.cpp index c122dc70..24dcd9b4 100644 --- a/tests/py-demo/bindings/src/modules/functions.cpp +++ b/tests/py-demo/bindings/src/modules/functions.cpp @@ -102,7 +102,6 @@ void bind_functions_module(py::module &&m) { m.def("pass_callback", [](std::function &callback) { return Foo(13); }); m.def("nested_types", [](std::variant, Foo> arg){ return arg; }); -#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12) py::options options; options.disable_function_signatures(); m.def( @@ -129,6 +128,13 @@ void bind_functions_module(py::module &&m) { "3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]\n"), py::arg("obj1") = py::none(), py::arg("obj2") = py::none()); - options.enable_function_signatures(); + m.def( + "passthrough_backwards", + [](py::object obj) { return obj; }, +#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12) + py::doc("passthrough_backwards[T](obj: T) -> T\n")); +#else + py::doc("passthrough_backwards(obj: T) -> T\n") #endif + options.enable_function_signatures(); } From 4ed02b431fbf0c2cb7cd27878b24e252cc948105 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 09:27:12 +0000 Subject: [PATCH 03/10] Fix syntax --- tests/py-demo/bindings/src/modules/functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/py-demo/bindings/src/modules/functions.cpp b/tests/py-demo/bindings/src/modules/functions.cpp index 24dcd9b4..42d959da 100644 --- a/tests/py-demo/bindings/src/modules/functions.cpp +++ b/tests/py-demo/bindings/src/modules/functions.cpp @@ -134,7 +134,7 @@ void bind_functions_module(py::module &&m) { #if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12) py::doc("passthrough_backwards[T](obj: T) -> T\n")); #else - py::doc("passthrough_backwards(obj: T) -> T\n") + py::doc("passthrough_backwards(obj: T) -> T\n")); #endif options.enable_function_signatures(); } From 33aa99b747f35035801ae322fff3e89d673d5a9a Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 09:38:15 +0000 Subject: [PATCH 04/10] Add 3.12 type hints --- .../demo/_bindings/functions.pyi | 2 ++ .../demo/_bindings/functions.pyi | 2 ++ .../numpy-array-use-type-var/demo/_bindings/functions.pyi | 2 ++ .../demo/_bindings/functions.pyi | 2 ++ .../demo/_bindings/functions.pyi | 2 ++ .../numpy-array-use-type-var/demo/_bindings/functions.pyi | 2 ++ .../demo/_bindings/functions.pyi | 2 ++ 7 files changed, 14 insertions(+) diff --git a/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index f5bf1819..0440b0b7 100644 --- a/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -23,6 +23,7 @@ __all__: list[str] = [ "passthrough1", "passthrough2", "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -68,5 +69,6 @@ def passthrough3() -> tuple[None, None]: ... def passthrough3[T](obj: T) -> tuple[T, None]: ... @typing.overload def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... +def passthrough_backwards[T](obj: T) -> T: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 2ae96f1a..bb839212 100644 --- a/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -24,6 +24,7 @@ __all__: list[str] = [ "passthrough1", "passthrough2", "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -70,5 +71,6 @@ def passthrough3() -> tuple[None, None]: ... def passthrough3[T](obj: T) -> tuple[T, None]: ... @typing.overload def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... +def passthrough_backwards[T](obj: T) -> T: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi index 2ae96f1a..bb839212 100644 --- a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -24,6 +24,7 @@ __all__: list[str] = [ "passthrough1", "passthrough2", "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -70,5 +71,6 @@ def passthrough3() -> tuple[None, None]: ... def passthrough3[T](obj: T) -> tuple[T, None]: ... @typing.overload def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... +def passthrough_backwards[T](obj: T) -> T: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 2ae96f1a..bb839212 100644 --- a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -24,6 +24,7 @@ __all__: list[str] = [ "passthrough1", "passthrough2", "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -70,5 +71,6 @@ def passthrough3() -> tuple[None, None]: ... def passthrough3[T](obj: T) -> tuple[T, None]: ... @typing.overload def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... +def passthrough_backwards[T](obj: T) -> T: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 4f239aa6..491ec41e 100644 --- a/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -22,6 +22,7 @@ __all__: list[str] = [ "passthrough1", "passthrough2", "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -66,5 +67,6 @@ def passthrough3() -> tuple[None, None]: ... def passthrough3[T](obj: T) -> tuple[T, None]: ... @typing.overload def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... +def passthrough_backwards[T](obj: T) -> T: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi index e6a83345..241af571 100644 --- a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -25,6 +25,7 @@ __all__: list[str] = [ "passthrough1", "passthrough2", "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -77,6 +78,7 @@ def passthrough3() -> tuple[None, None]: ... def passthrough3[T](obj: T) -> tuple[T, None]: ... @typing.overload def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... +def passthrough_backwards[T](obj: T) -> T: ... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... diff --git a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index e6a83345..241af571 100644 --- a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -25,6 +25,7 @@ __all__: list[str] = [ "passthrough1", "passthrough2", "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -77,6 +78,7 @@ def passthrough3() -> tuple[None, None]: ... def passthrough3[T](obj: T) -> tuple[T, None]: ... @typing.overload def passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2]: ... +def passthrough_backwards[T](obj: T) -> T: ... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... From 3cafc2cd52cebcbf251c793cb8c05cde0b5dfa1a Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 09:38:28 +0000 Subject: [PATCH 05/10] Add typevar --- tests/py-demo/bindings/src/modules/functions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/py-demo/bindings/src/modules/functions.cpp b/tests/py-demo/bindings/src/modules/functions.cpp index 42d959da..56f0fafb 100644 --- a/tests/py-demo/bindings/src/modules/functions.cpp +++ b/tests/py-demo/bindings/src/modules/functions.cpp @@ -134,7 +134,8 @@ void bind_functions_module(py::module &&m) { #if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12) py::doc("passthrough_backwards[T](obj: T) -> T\n")); #else - py::doc("passthrough_backwards(obj: T) -> T\n")); + py::doc("passthrough_backwards(obj: U) -> U\n")); + m.attr("U") = py::module::import("typing").attr("TypeVar")("U"); #endif options.enable_function_signatures(); } From f154869c9fa47de38930844e45adeb1c3536697b Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 10:54:07 +0000 Subject: [PATCH 06/10] Fix stubgen and stubs --- pybind11_stubgen/parser/mixins/parse.py | 23 ++++++++++++------- .../demo/_bindings/functions.pyi | 20 ++++++++++++++++ .../demo/_bindings/functions.pyi | 20 ++++++++++++++++ .../demo/_bindings/functions.pyi | 20 ++++++++++++++++ .../demo/_bindings/functions.pyi | 20 ++++++++++++++++ .../demo/_bindings/functions.pyi | 20 ++++++++++++++++ .../demo/_bindings/functions.pyi | 20 ++++++++++++++++ .../demo/_bindings/functions.pyi | 20 ++++++++++++++++ 8 files changed, 155 insertions(+), 8 deletions(-) diff --git a/pybind11_stubgen/parser/mixins/parse.py b/pybind11_stubgen/parser/mixins/parse.py index db044739..13d778af 100644 --- a/pybind11_stubgen/parser/mixins/parse.py +++ b/pybind11_stubgen/parser/mixins/parse.py @@ -629,11 +629,9 @@ def parse_function_docstring( if len(doc_lines) == 0: return [] - type_var_pattern = re.compile(r"(\[(?P[\w\s,]*)])?") - top_signature_regex = re.compile( - rf"^{func_name}" + - type_var_pattern.pattern * ((1, 12) <= sys.version_info) + + rf"^{func_name}" + r"(\[(?P[\w\s,]*)])?" r"\((?P.*)\)\s*(->\s*(?P.+))?$" ) @@ -644,9 +642,13 @@ def parse_function_docstring( if len(doc_lines) < 2 or doc_lines[1] != "Overloaded function.": # TODO: Update to support more complex formats. # This only supports bare type parameters. + type_vars_group = match.group("type_vars") + if sys.version_info < (3, 12) and type_vars_group: + # This syntax is not supported before Python 3.12. + return [] type_vars: list[str] = list( filter( - bool, map(str.strip, (match.group("type_vars") or "").split(",")) + bool, map(str.strip, (type_vars_group or "").split(",")) ) ) args = self.call_with_local_types( @@ -672,8 +674,8 @@ def parse_function_docstring( ] overload_signature_regex = re.compile( - rf"^(\s*(?P\d+)\.\s*){func_name}" + - type_var_pattern.pattern * ((1, 12) <= sys.version_info) + + rf"^(\s*(?P\d+)\.\s*){func_name}" + r"(\[(?P[\w\s,]*)])?" r"\((?P.*)\)\s*->\s*(?P.+)$" ) @@ -686,14 +688,19 @@ def parse_function_docstring( if match: if match.group("overload_number") != f"{len(overloads)}": continue + type_vars_group = match.group("type_vars") + if sys.version_info < (3, 12) and type_vars_group: + # This syntax is not supported before Python 3.12. + continue overloads[-1].doc = self._strip_empty_lines(doc_lines[doc_start:i]) doc_start = i + 1 # TODO: Update to support more complex formats. # This only supports bare type parameters. + type_vars: list[str] = list( filter( bool, - map(str.strip, (match.group("type_vars") or "").split(",")), + map(str.strip, (type_vars_group or "").split(",")), ) ) args = self.call_with_local_types( diff --git a/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 316386c8..c26343f5 100644 --- a/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -20,6 +20,10 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -54,5 +58,21 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1(*args, **kwargs: typing.Any): + """ + passthrough1[T](obj: T) -> T + """ +@typing.overload +def passthrough2() -> None: + """ + 2. passthrough2[T](obj: T) -> T + """ +@typing.overload +def passthrough3() -> tuple[None, None]: + """ + 2. passthrough3[T](obj: T) -> tuple[T, None] + 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] + """ +def passthrough_backwards(obj: U) -> U: def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 72ab6498..08472438 100644 --- a/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -21,6 +21,10 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -56,5 +60,21 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1(*args, **kwargs: typing.Any): + """ + passthrough1[T](obj: T) -> T + """ +@typing.overload +def passthrough2() -> None: + """ + 2. passthrough2[T](obj: T) -> T + """ +@typing.overload +def passthrough3() -> tuple[None, None]: + """ + 2. passthrough3[T](obj: T) -> tuple[T, None] + 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] + """ +def passthrough_backwards(obj: U) -> U: def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi index 72ab6498..08472438 100644 --- a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -21,6 +21,10 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -56,5 +60,21 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1(*args, **kwargs: typing.Any): + """ + passthrough1[T](obj: T) -> T + """ +@typing.overload +def passthrough2() -> None: + """ + 2. passthrough2[T](obj: T) -> T + """ +@typing.overload +def passthrough3() -> tuple[None, None]: + """ + 2. passthrough3[T](obj: T) -> tuple[T, None] + 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] + """ +def passthrough_backwards(obj: U) -> U: def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 72ab6498..08472438 100644 --- a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -21,6 +21,10 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -56,5 +60,21 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1(*args, **kwargs: typing.Any): + """ + passthrough1[T](obj: T) -> T + """ +@typing.overload +def passthrough2() -> None: + """ + 2. passthrough2[T](obj: T) -> T + """ +@typing.overload +def passthrough3() -> tuple[None, None]: + """ + 2. passthrough3[T](obj: T) -> tuple[T, None] + 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] + """ +def passthrough_backwards(obj: U) -> U: def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 2f467b68..be9faa49 100644 --- a/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -19,6 +19,10 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -52,5 +56,21 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1(*args, **kwargs: typing.Any): + """ + passthrough1[T](obj: T) -> T + """ +@typing.overload +def passthrough2() -> None: + """ + 2. passthrough2[T](obj: T) -> T + """ +@typing.overload +def passthrough3() -> tuple[None, None]: + """ + 2. passthrough3[T](obj: T) -> tuple[T, None] + 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] + """ +def passthrough_backwards(obj: U) -> U: def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi index f24c3270..bbe9ea85 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -22,6 +22,10 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -63,6 +67,22 @@ def mul(p: typing.SupportsFloat, q: typing.SupportsFloat) -> float: def nested_types(arg0: collections.abc.Sequence[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: collections.abc.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1(*args, **kwargs: typing.Any): + """ + passthrough1[T](obj: T) -> T + """ +@typing.overload +def passthrough2() -> None: + """ + 2. passthrough2[T](obj: T) -> T + """ +@typing.overload +def passthrough3() -> tuple[None, None]: + """ + 2. passthrough3[T](obj: T) -> tuple[T, None] + 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] + """ +def passthrough_backwards(obj: U) -> U: def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index f24c3270..bbe9ea85 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -22,6 +22,10 @@ __all__: list[str] = [ "mul", "nested_types", "pass_callback", + "passthrough1", + "passthrough2", + "passthrough3", + "passthrough_backwards", "pos_kw_only_mix", "pos_kw_only_variadic_mix", ] @@ -63,6 +67,22 @@ def mul(p: typing.SupportsFloat, q: typing.SupportsFloat) -> float: def nested_types(arg0: collections.abc.Sequence[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: collections.abc.Callable[[Foo], Foo]) -> Foo: ... +def passthrough1(*args, **kwargs: typing.Any): + """ + passthrough1[T](obj: T) -> T + """ +@typing.overload +def passthrough2() -> None: + """ + 2. passthrough2[T](obj: T) -> T + """ +@typing.overload +def passthrough3() -> tuple[None, None]: + """ + 2. passthrough3[T](obj: T) -> tuple[T, None] + 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] + """ +def passthrough_backwards(obj: U) -> U: def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... From e2f567cdfbb17ea4809a97ad5d770d51c8a69f7e Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 11:04:35 +0000 Subject: [PATCH 07/10] Fix stubs --- .../demo/_bindings/functions.pyi | 10 ++++++++-- .../demo/_bindings/functions.pyi | 10 ++++++++-- .../demo/_bindings/functions.pyi | 10 ++++++++-- .../demo/_bindings/functions.pyi | 10 ++++++++-- .../demo/_bindings/functions.pyi | 10 ++++++++-- .../demo/_bindings/functions.pyi | 8 +++++++- .../demo/_bindings/functions.pyi | 8 +++++++- 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index c26343f5..6ed5b9f2 100644 --- a/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -4,6 +4,7 @@ import typing __all__: list[str] = [ "Foo", + "U", "accept_callable", "accept_frozenset", "accept_py_handle", @@ -58,21 +59,26 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... -def passthrough1(*args, **kwargs: typing.Any): +def passthrough1(*args, **kwargs): """ passthrough1[T](obj: T) -> T """ + @typing.overload def passthrough2() -> None: """ 2. passthrough2[T](obj: T) -> T """ + @typing.overload def passthrough3() -> tuple[None, None]: """ 2. passthrough3[T](obj: T) -> tuple[T, None] 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U: + +def passthrough_backwards(obj: U) -> U:... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... + +U: typing.TypeVar # value = ~U diff --git a/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 08472438..0a287776 100644 --- a/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -4,6 +4,7 @@ import typing __all__: list[str] = [ "Foo", + "U", "accept_annotated_callable", "accept_callable", "accept_frozenset", @@ -60,21 +61,26 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... -def passthrough1(*args, **kwargs: typing.Any): +def passthrough1(*args, **kwargs): """ passthrough1[T](obj: T) -> T """ + @typing.overload def passthrough2() -> None: """ 2. passthrough2[T](obj: T) -> T """ + @typing.overload def passthrough3() -> tuple[None, None]: """ 2. passthrough3[T](obj: T) -> tuple[T, None] 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U: + +def passthrough_backwards(obj: U) -> U:... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... + +U: typing.TypeVar # value = ~U diff --git a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi index 08472438..0a287776 100644 --- a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -4,6 +4,7 @@ import typing __all__: list[str] = [ "Foo", + "U", "accept_annotated_callable", "accept_callable", "accept_frozenset", @@ -60,21 +61,26 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... -def passthrough1(*args, **kwargs: typing.Any): +def passthrough1(*args, **kwargs): """ passthrough1[T](obj: T) -> T """ + @typing.overload def passthrough2() -> None: """ 2. passthrough2[T](obj: T) -> T """ + @typing.overload def passthrough3() -> tuple[None, None]: """ 2. passthrough3[T](obj: T) -> tuple[T, None] 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U: + +def passthrough_backwards(obj: U) -> U:... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... + +U: typing.TypeVar # value = ~U diff --git a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 08472438..0a287776 100644 --- a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -4,6 +4,7 @@ import typing __all__: list[str] = [ "Foo", + "U", "accept_annotated_callable", "accept_callable", "accept_frozenset", @@ -60,21 +61,26 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... -def passthrough1(*args, **kwargs: typing.Any): +def passthrough1(*args, **kwargs): """ passthrough1[T](obj: T) -> T """ + @typing.overload def passthrough2() -> None: """ 2. passthrough2[T](obj: T) -> T """ + @typing.overload def passthrough3() -> tuple[None, None]: """ 2. passthrough3[T](obj: T) -> tuple[T, None] 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U: + +def passthrough_backwards(obj: U) -> U:... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... + +U: typing.TypeVar # value = ~U diff --git a/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index be9faa49..9b2ab5c3 100644 --- a/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -4,6 +4,7 @@ import typing __all__: list[str] = [ "Foo", + "U", "accept_callable", "accept_py_handle", "accept_py_object", @@ -56,21 +57,26 @@ def mul(p: float, q: float) -> float: def nested_types(arg0: list[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: typing.Callable[[Foo], Foo]) -> Foo: ... -def passthrough1(*args, **kwargs: typing.Any): +def passthrough1(*args, **kwargs): """ passthrough1[T](obj: T) -> T """ + @typing.overload def passthrough2() -> None: """ 2. passthrough2[T](obj: T) -> T """ + @typing.overload def passthrough3() -> tuple[None, None]: """ 2. passthrough3[T](obj: T) -> tuple[T, None] 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U: + +def passthrough_backwards(obj: U) -> U:... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... + +U: typing.TypeVar # value = ~U diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi index bbe9ea85..d686bbca 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -5,6 +5,7 @@ import typing __all__: list[str] = [ "Foo", + "U", "accept_annotated_callable", "accept_callable", "accept_frozenset", @@ -71,18 +72,21 @@ def passthrough1(*args, **kwargs: typing.Any): """ passthrough1[T](obj: T) -> T """ + @typing.overload def passthrough2() -> None: """ 2. passthrough2[T](obj: T) -> T """ + @typing.overload def passthrough3() -> tuple[None, None]: """ 2. passthrough3[T](obj: T) -> tuple[T, None] 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U: + +def passthrough_backwards(obj: U) -> U:... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... @@ -94,3 +98,5 @@ def pos_kw_only_variadic_mix( k: typing.SupportsInt, **kwargs, ) -> tuple: ... + +U: typing.TypeVar # value = ~U diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index bbe9ea85..d686bbca 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -5,6 +5,7 @@ import typing __all__: list[str] = [ "Foo", + "U", "accept_annotated_callable", "accept_callable", "accept_frozenset", @@ -71,18 +72,21 @@ def passthrough1(*args, **kwargs: typing.Any): """ passthrough1[T](obj: T) -> T """ + @typing.overload def passthrough2() -> None: """ 2. passthrough2[T](obj: T) -> T """ + @typing.overload def passthrough3() -> tuple[None, None]: """ 2. passthrough3[T](obj: T) -> tuple[T, None] 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U: + +def passthrough_backwards(obj: U) -> U:... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... @@ -94,3 +98,5 @@ def pos_kw_only_variadic_mix( k: typing.SupportsInt, **kwargs, ) -> tuple: ... + +U: typing.TypeVar # value = ~U From 88e60226c1503d31a62768487110938aa525b598 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 11:13:11 +0000 Subject: [PATCH 08/10] Fix formatting --- .../demo/_bindings/functions.pyi | 2 +- .../demo/_bindings/functions.pyi | 2 +- .../numpy-array-use-type-var/demo/_bindings/functions.pyi | 2 +- .../demo/_bindings/functions.pyi | 2 +- .../demo/_bindings/functions.pyi | 2 +- .../numpy-array-use-type-var/demo/_bindings/functions.pyi | 2 +- .../demo/_bindings/functions.pyi | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 6ed5b9f2..264c8011 100644 --- a/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -77,7 +77,7 @@ def passthrough3() -> tuple[None, None]: 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U:... +def passthrough_backwards(obj: U) -> U: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 0a287776..df1fc8f1 100644 --- a/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -79,7 +79,7 @@ def passthrough3() -> tuple[None, None]: 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U:... +def passthrough_backwards(obj: U) -> U: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi index 0a287776..df1fc8f1 100644 --- a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -79,7 +79,7 @@ def passthrough3() -> tuple[None, None]: 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U:... +def passthrough_backwards(obj: U) -> U: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 0a287776..df1fc8f1 100644 --- a/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -79,7 +79,7 @@ def passthrough3() -> tuple[None, None]: 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U:... +def passthrough_backwards(obj: U) -> U: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 9b2ab5c3..63de1c09 100644 --- a/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v2.9/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -75,7 +75,7 @@ def passthrough3() -> tuple[None, None]: 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U:... +def passthrough_backwards(obj: U) -> U: ... def pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple: ... def pos_kw_only_variadic_mix(i: int, /, j: int, *args, k: int, **kwargs) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi index d686bbca..52df183e 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -86,7 +86,7 @@ def passthrough3() -> tuple[None, None]: 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U:... +def passthrough_backwards(obj: U) -> U: ... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index d686bbca..52df183e 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -86,7 +86,7 @@ def passthrough3() -> tuple[None, None]: 3. passthrough3[T1, T2](obj1: T1, obj2: T2) -> tuple[T1, T2] """ -def passthrough_backwards(obj: U) -> U:... +def passthrough_backwards(obj: U) -> U: ... def pos_kw_only_mix( i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt ) -> tuple: ... From 1ba7176d4abe49f5c21329abad51ff08b2a59959 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 11:23:38 +0000 Subject: [PATCH 09/10] Reformat and fix stubs --- pybind11_stubgen/parser/mixins/parse.py | 2 +- .../numpy-array-use-type-var/demo/_bindings/functions.pyi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pybind11_stubgen/parser/mixins/parse.py b/pybind11_stubgen/parser/mixins/parse.py index 13d778af..c901c24f 100644 --- a/pybind11_stubgen/parser/mixins/parse.py +++ b/pybind11_stubgen/parser/mixins/parse.py @@ -3,9 +3,9 @@ import ast import inspect import re +import sys import types from typing import Any, Callable, TypeVar -import sys from pybind11_stubgen.parser.errors import ( InvalidExpressionError, diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi index 52df183e..beb13c51 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/functions.pyi @@ -68,7 +68,7 @@ def mul(p: typing.SupportsFloat, q: typing.SupportsFloat) -> float: def nested_types(arg0: collections.abc.Sequence[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: collections.abc.Callable[[Foo], Foo]) -> Foo: ... -def passthrough1(*args, **kwargs: typing.Any): +def passthrough1(*args, **kwargs): """ passthrough1[T](obj: T) -> T """ From bb9d6bae8f931b27a7d77421eda9a4fde2c74228 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Thu, 5 Feb 2026 11:25:54 +0000 Subject: [PATCH 10/10] Remove kwargs type hint --- .../demo/_bindings/functions.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi index 52df183e..beb13c51 100644 --- a/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi +++ b/tests/stubs/python-3.11/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/functions.pyi @@ -68,7 +68,7 @@ def mul(p: typing.SupportsFloat, q: typing.SupportsFloat) -> float: def nested_types(arg0: collections.abc.Sequence[Foo] | Foo) -> list[Foo] | Foo: ... def pass_callback(arg0: collections.abc.Callable[[Foo], Foo]) -> Foo: ... -def passthrough1(*args, **kwargs: typing.Any): +def passthrough1(*args, **kwargs): """ passthrough1[T](obj: T) -> T """