8000 improve stubgen tests · python/mypy@ff885c3 · GitHub
[go: up one dir, main page]

Skip to content

Commit ff885c3

Browse files
committed
improve stubgen tests
1 parent fbb738a commit ff885c3

File tree

8 files changed

+158
-32
lines changed

8 files changed

+158
-32
lines changed

misc/test-stubgenc.sh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,24 @@ function stubgenc_test() {
2121
rm -rf "${STUBGEN_OUTPUT_FOLDER:?}/*"
2222
stubgen -o "$STUBGEN_OUTPUT_FOLDER" "${@:2}"
2323

24+
# Check if generated stubs can actually be type checked by mypy
25+
if ! mypy "$STUBGEN_OUTPUT_FOLDER";
26+
then
27+
echo "Stubgen test failed, because generated stubs failed to type check."
28+
EXIT=1
29+
fi
30+
2431
# Compare generated stubs to expected ones
2532
if ! git diff --exit-code "$STUBGEN_OUTPUT_FOLDER";
2633
then
34+
echo "Stubgen test failed, because generated stubs differ from expected outputs."
2735
EXIT=1
2836
fi
2937
}
3038

3139
# create stubs without docstrings
32-
stubgenc_test stubgen -p pybind11_mypy_demo
40+
stubgenc_test expected_stubs_no_docs -p pybind11_mypy_demo
3341
# create stubs with docstrings
34-
stubgenc_test stubgen-include-docs -p pybind11_mypy_demo --include-docstrings
42+
stubgenc_test expected_stubs_with_docs -p pybind11_mypy_demo --include-docstrings
43+
3544
exit $EXIT
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import os
2+
from . import demo as demo
3+
from typing import List, Optional, Tuple
4+
5+
class TestStruct:
6+
field_readwrite: int
7+
field_readwrite_docstring: int
8+
def __init__(self, *args, **kwargs) -> None: ...
9+
@property
10+
def field_readonly(self) -> int: ...
11+
12+
def func_incomplete_signature(*args, **kwargs): ...
13+
def func_returning_optional() -> Optional[int]: ...
14+
def func_returning_pair() -> Tuple[int, float]: ...
15+
def func_returning_path() -> os.PathLike: ...
16+
def func_returning_vector() -> List[float]: ...
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import os
2+
from . import demo as demo
3+
from typing import List, Optional, Tuple
4+
5+
class TestStruct:
6+
field_readwrite: int
7+
field_readwrite_docstring: int
8+
def __init__(self, *args, **kwargs) -> None:
9+
"""Initialize self. See help(type(self)) for accurate signature."""
10+
@property
11+
def field_readonly(self) -> int: ...
12+
13+
def func_incomplete_signature(*args, **kwargs):
14+
"""func_incomplete_signature() -> dummy_sub_namespace::HasNoBinding"""
15+
def func_returning_optional() -> Optional[int]:
16+
"""func_returning_optional() -> Optional[int]"""
17+
def func_returning_pair() -> Tuple[int, float]:
18+
"""func_returning_pair() -> Tuple[int, float]"""
19+
def func_returning_path() -> os.PathLike:
20+
"""func_returning_path() -> os.PathLike"""
21+
def func_returning_vector() -> List[float]:
22+
"""func_returning_vector() -> List[float]"""

test-data/pybind11_mypy_demo/stubgen-include-docs/pybind11_mypy_demo/basics.pyi renamed to test-data/pybind11_mypy_demo/expected_stubs_with_docs/pybind11_mypy_demo/demo.pyi

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ class Point:
1010
degree: ClassVar[Point.AngleUnit] = ...
1111
radian: ClassVar[Point.AngleUnit] = ...
1212
def __init__(self, value: int) -> None:
13-
"""__init__(self: pybind11_mypy_demo.basics.Point.AngleUnit, value: int) -> None"""
13+
"""__init__(self: pybind11_mypy_demo.demo.Point.AngleUnit, value: int) -> None"""
1414
def __eq__(self, other: object) -> bool:
1515
"""__eq__(self: object, other: object) -> bool"""
1616
def __hash__(self) -> int:
1717
"""__hash__(self: object) -> int"""
1818
def __index__(self) -> int:
19-
"""__index__(self: pybind11_mypy_demo.basics.Point.AngleUnit) -> int"""
19+
"""__index__(self: pybind11_mypy_demo.demo.Point.AngleUnit) -> int"""
2020
def __int__(self) -> int:
21-
"""__int__(self: pybind11_mypy_demo.basics.Point.AngleUnit) -> int"""
21+
"""__int__(self: pybind11_mypy_demo.demo.Point.AngleUnit) -> int"""
2222
def __ne__(self, other: object) -> bool:
2323
"""__ne__(self: object, other: object) -> bool"""
2424
@property
@@ -33,15 +33,15 @@ class Point:
3333
mm: ClassVar[Point.LengthUnit] = ...
3434
pixel: ClassVar[Point.LengthUnit] = ...
3535
def __init__(self, value: int) -> None:
36-
"""__init__(self: pybind11_mypy_demo.basics.Point.LengthUnit, value: int) -> None"""
36+
"""__init__(self: pybind11_mypy_demo.demo.Point.LengthUnit, value: int) -> None"""
3737
def __eq__(self, other: object) -> bool:
3838
"""__eq__(self: object, other: object) -> bool"""
3939
def __hash__(self) -> int:
4040
"""__hash__(self: object) -> int"""
4141
def __index__(self) -> int:
42-
"""__index__(self: pybind11_mypy_demo.basics.Point.LengthUnit) -> int"""
42+
"""__index__(self: pybind11_mypy_demo.demo.Point.LengthUnit) -> int"""
4343
def __int__(self) -> int:
44-
"""__int__(self: pybind11_mypy_demo.basics.Point.LengthUnit) -> int"""
44+
"""__int__(self: pybind11_mypy_demo.demo.Point.LengthUnit) -> int"""
4545
def __ne__(self, other: object) -> bool:
4646
"""__ne__(self: object, other: object) -> bool"""
4747
@property
@@ -60,38 +60,38 @@ class Point:
6060
"""__init__(*args, **kwargs)
6161
Overloaded function.
6262
63-
1. __init__(self: pybind11_mypy_demo.basics.Point) -> None
63+
1. __init__(self: pybind11_mypy_demo.demo.Point) -> None
6464
65-
2. __init__(self: pybind11_mypy_demo.basics.Point, x: float, y: float) -> None
65+
2. __init__(self: pybind11_mypy_demo.demo.Point, x: float, y: float) -> None
6666
"""
6767
@overload
6868
def __init__(self, x: float, y: float) -> None:
6969
"""__init__(*args, **kwargs)
7070
Overloaded function.
7171
72-
1. __init__(self: pybind11_mypy_demo.basics.Point) -> None
72+
1. __init__(self: pybind11_mypy_demo.demo.Point) -> None
7373
74-
2. __init__(self: pybind11_mypy_demo.basics.Point, x: float, y: float) -> None
74+
2. __init__(self: pybind11_mypy_demo.demo.Point, x: float, y: float) -> None
7575
"""
7676
def as_list(self) -> List[float]:
77-
"""as_list(self: pybind11_mypy_demo.basics.Point) -> List[float]"""
77+
"""as_list(self: pybind11_mypy_demo.demo.Point) -> List[float]"""
7878
@overload
7979
def distance_to(self, x: float, y: float) -> float:
8080
"""distance_to(*args, **kwargs)
8181
Overloaded function.
8282
83-
1. distance_to(self: pybind11_mypy_demo.basics.Point, x: float, y: float) -> float
83+
1. distance_to(self: pybind11_mypy_demo.demo.Point, x: float, y: float) -> float
8484
85-
2. distance_to(self: pybind11_mypy_demo.basics.Point, other: pybind11_mypy_demo.basics.Point) -> float
85+
2. distance_to(self: pybind11_mypy_demo.demo.Point, other: pybind11_mypy_demo.demo.Point) -> float
8686
"""
8787
@overload
8888
def distance_to(self, other: Point) -> float:
8989
"""distance_to(*args, **kwargs)
9090
Overloaded function.
9191
92-
1. distance_to(self: pybind11_mypy_demo.basics.Point, x: float, y: float) -> float
92+
1. distance_to(self: pybind11_mypy_demo.demo.Point, x: float, y: float) -> float
9393
94-
2. distance_to(self: pybind11_mypy_demo.basics.Point, other: pybind11_mypy_demo.basics.Point) -> float
94+
2. distance_to(self: pybind11_mypy_demo.demo.Point, other: pybind11_mypy_demo.demo.Point) -> float
9595
"""
9696
@property
9797
def length(self) -> float: ...

test-data/pybind11_mypy_demo/src/main.cpp

Lines changed: 94 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,85 @@
4343
*/
4444

4545
#include <cmath>
46+
#include <filesystem>
47+
#include <optional>
48+
#include <utility>
49+
#include <vector>
50+
4651
#include <pybind11/pybind11.h>
4752
#include <pybind11/stl.h>
53+
#include <pybind11/stl/filesystem.h>
4854

4955
namespace py = pybind11;
5056

51-
namespace basics {
57+
// ----------------------------------------------------------------------------
58+
// Dedicated test cases
59+
// ----------------------------------------------------------------------------
60+
61+
std::vector<float> funcReturningVector()
62+
{
63+
return std::vector<float>{1.0, 2.0, 3.0};
64+
}
65+
66+
std::pair<int, float> funcReturningPair()
67+
{
68+
return std::pair{42, 1.0};
69+
}
70+
71+
std::optional<int> funcReturningOptional()
72+
{
73+
return std::nullopt;
74+
}
75+
76+
std::filesystem::path funcReturningPath()
77+
{
78+
return std::filesystem::path{"foobar"};
79+
}
80+
81+
namespace dummy_sub_namespace {
82+
struct HasNoBinding{};
83+
}
84+
85+
// We can enforce the case of an incomplete signature by referring to a type in
86+
// some namespace that doesn't have a pybind11 binding.
87+
dummy_sub_namespace::HasNoBinding funcIncompleteSignature()
88+
{
89+
return dummy_sub_namespace::HasNoBinding{};
90+
}
91+
92+
struct TestStruct
93+
{
94+
int field_readwrite;
95+
int field_readwrite_docstring;
96+
int field_readonly;
97+
};
98+
99+
// Bindings
100+
101+
void bind_test_cases(py::module& m) {
102+
m.def("func_returning_vector", &funcReturningVector);
103+
m.def("func_returning_pair", &funcReturningPair);
104+
m.def("func_returning_optional", &funcReturningOptional);
105+
m.def("func_returning_path", &funcReturningPath);
106+
107+
m.def("func_incomplete_signature", &funcIncompleteSignature);
108+
109+
py::class_<TestStruct>(m, "TestStruct")
110+
.def_readwrite("field_readwrite", &TestStruct::field_readwrite)
111+
.def_readwrite("field_readwrite_docstring", &TestStruct::field_readwrite_docstring, "some docstring")
112+
.def_property_readonly(
113+
"field_readonly",
114+
[](const TestStruct& x) {
115+
return x.field_readonly;
116+
},
117+
"some docstring");
118+
}
119+
120+
// ----------------------------------------------------------------------------
121+
// Original demo
122+
// ----------------------------------------------------------------------------
123+
124+
namespace demo {
52125

53126
int answer() {
54127
return 42;
@@ -118,20 +191,22 @@ const Point Point::y_axis = Point(0, 1);
118191
Point::LengthUnit Point::length_unit = Point::LengthUnit::mm;
119192
Point::AngleUnit Point::angle_unit = Point::AngleUnit::radian;
120193

121-
} // namespace: basics
194+
} // namespace: demo
122195

123-
void bind_basics(py::module& basics) {
196+
// Bindings
124197

125-
using namespace basics;
198+
void bind_demo(py::module& m) {
199+
200+
using namespace demo;
126201

127202
// Functions
128-
basics.def("answer", &answer, "answer docstring, with end quote\""); // tests explicit docstrings
129-
basics.def("sum", &sum, "multiline docstring test, edge case quotes \"\"\"'''");
130-
basics.def("midpoint", &midpoint, py::arg("left"), py::arg("right"));
131-
basics.def("weighted_midpoint", weighted_midpoint, py::arg("left"), py::arg("right"), py::arg("alpha")=0.5);
203+
m.def("answer", &answer, "answer docstring, with end quote\""); // tests explicit docstrings
204+
m.def("sum", &sum, "multiline docstring test, edge case quotes \"\"\"'''");
205+
m.def("midpoint", &midpoint, py::arg("left"), py::arg("right"));
206+
m.def("weighted_midpoint", weighted_midpoint, py::arg("left"), py::arg("right"), py::arg("alpha")=0.5);
132207

133208
// Classes
134-
py::class_<Point> pyPoint(basics, "Point");
209+
py::class_<Point> pyPoint(m, "Point");
135210
py::enum_<Point::LengthUnit> pyLengthUnit(pyPoint, "LengthUnit");
136211
py::enum_<Point::AngleUnit> pyAngleUnit(pyPoint, "AngleUnit");
137212

@@ -167,11 +242,17 @@ void bind_basics(py::module& basics) {
167242
.value("degree", Point::AngleUnit::degree);
168243

169244
// Module-level attributes
170-
basics.attr("PI") = std::acos(-1);
171-
basics.attr("__version__") = "0.0.1";
245+
m.attr("PI") = std::acos(-1);
246+
m.attr("__version__") = "0.0.1";
172247
}
173248

249+
// ----------------------------------------------------------------------------
250+
// Module entry point
251+
// ----------------------------------------------------------------------------
252+
174253
PYBIND11_MODULE(pybind11_mypy_demo, m) {
175-
auto basics = m.def_submodule("basics");
176-
bind_basics(basics);
254+
bind_test_cases(m);
255+
256+
auto demo = m.def_submodule("demo");
257+
bind_demo(demo);
177258
}

test-data/pybind11_mypy_demo/stubgen-include-docs/pybind11_mypy_demo/__init__.pyi

Lines changed: 0 additions & 1 deletion
This file was deleted.

test-data/pybind11_mypy_demo/stubgen/pybind11_mypy_demo/__init__.pyi

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)
0