Skip to content

Commit b096ca3

Browse files
committed
Add example test for stubgen/mypy error
1 parent 30d4dd2 commit b096ca3

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ set(PYBIND11_TEST_FILES
170170
test_stl
171171
test_stl_binders
172172
test_stubgen
173+
test_stubgen_error
173174
test_tagbased_polymorphic
174175
test_thread
175176
test_type_caster_pyobject_ptr

tests/test_stubgen.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,31 @@
22

33
from pathlib import Path
44

5-
import pybind11_stubgen as stubgen
5+
import pybind11_stubgen
66
from mypy import api
77

88
from pybind11_tests import stubgen as m
99

1010

1111
def test_stubgen(tmp_path: Path) -> None:
1212
assert m.add_int(1, 2) == 3
13-
14-
stubgen.main(
13+
# Generate stub into temporary directory
14+
pybind11_stubgen.main(
1515
[
1616
"pybind11_tests.stubgen",
1717
"-o",
1818
tmp_path.as_posix(),
1919
]
2020
)
21-
print(f"Stubgen output: {tmp_path.as_posix()}")
21+
# Check stub file is generated and contains expected content
2222
stub_file = tmp_path / "pybind11_tests" / "stubgen.pyi"
2323
assert stub_file.exists()
2424
stub_content = stub_file.read_text()
2525
assert (
2626
"def add_int(a: typing.SupportsInt, b: typing.SupportsInt) -> int:"
2727
in stub_content
2828
)
29+
# Run mypy on the generated stub file
2930
normal_report, error_report, exit_status = api.run([stub_file.as_posix()])
3031
print("Normal report:")
3132
print(normal_report)

tests/test_stubgen_error.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "pybind11_tests.h"
2+
3+
TEST_SUBMODULE(stubgen_error, m) {
4+
m.def("identity_capsule", [](py::capsule c) { return c; }, "c"_a);
5+
}

tests/test_stubgen_error.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from __future__ import annotations
2+
3+
import sys
4+
from pathlib import Path
5+
6+
import pybind11_stubgen
7+
import pytest
8+
from mypy import api
9+
10+
from pybind11_tests import stubgen_error as m
11+
12+
13+
@pytest.mark.skipif(
14+
sys.version_info >= (3, 13), reason="CapsuleType available in 3.13+"
15+
)
16+
def test_stubgen(tmp_path: Path, caplog: pytest.LogCaptureFixture) -> None:
17+
"""Show stubgen/mypy errors for CapsuleType (not available in Python < 3.13)."""
18+
assert m.identity_capsule(None) is None
19+
# Generate stub into temporary directory
20+
pybind11_stubgen.main(
21+
[
22+
"pybind11_tests.stubgen_error",
23+
"-o",
24+
tmp_path.as_posix(),
25+
]
26+
)
27+
# Errors are reported using logging
28+
assert "Can't find/import 'types.CapsuleType'" in caplog.text
29+
# Stub file is still generated if error is not fatal
30+
stub_file = tmp_path / "pybind11_tests" / "stubgen_error.pyi"
31+
assert stub_file.exists()
32+
stub_content = stub_file.read_text()
33+
assert (
34+
"def identity_capsule(c: types.CapsuleType) -> types.CapsuleType:"
35+
in stub_content
36+
)
37+
# Run mypy on the generated stub file
38+
# normal_report -> stdout, error_report -> stderr
39+
# Type errors seem to go into normal_report
40+
normal_report, error_report, exit_status = api.run([stub_file.as_posix()])
41+
print("Normal report:")
42+
print(normal_report)
43+
print("Error report:")
44+
print(error_report)
45+
assert exit_status == 1
46+
assert 'error: Name "types" is not defined [name-defined]' in normal_report

0 commit comments

Comments
 (0)