Skip to content

Commit f7e94ee

Browse files
bluenote10Keller Fabian Rudolf (CC-AD/EYC3)
and
Keller Fabian Rudolf (CC-AD/EYC3)
authored
Make pybind11 test fixture fully self-contained (#12722)
Co-authored-by: Keller Fabian Rudolf (CC-AD/EYC3) <[email protected]>
1 parent e93be73 commit f7e94ee

File tree

6 files changed

+212
-5
lines changed

6 files changed

+212
-5
lines changed

misc/test-stubgenc.sh

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
#!/bin/bash
2-
# This script is expected to be run from root of the mypy repo
2+
3+
set -e
4+
set -x
5+
6+
cd "$(dirname $0)/.."
37

48
# Install dependencies, demo project and mypy
59
python -m pip install -r test-requirements.txt
6-
python -m pip install pybind11-mypy-demo==0.0.1
10+
python -m pip install ./test-data/pybind11_mypy_demo
711
python -m pip install .
812

913
# Remove expected stubs and generate new inplace
10-
rm -rf test-data/stubgen/pybind11_mypy_demo
11-
stubgen -p pybind11_mypy_demo -o test-data/stubgen/
14+
STUBGEN_OUTPUT_FOLDER=./test-data/pybind11_mypy_demo/stubgen
15+
rm -rf $STUBGEN_OUTPUT_FOLDER/*
16+
stubgen -p pybind11_mypy_demo -o $STUBGEN_OUTPUT_FOLDER
1217

1318
# Compare generated stubs to expected ones
14-
git diff --exit-code test-data/stubgen/pybind11_mypy_demo
19+
git diff --exit-code $STUBGEN_OUTPUT_FOLDER
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[build-system]
2+
requires = [
3+
"setuptools>=42",
4+
"wheel",
5+
# Officially supported pybind11 version. This is pinned to guarantee 100% reproducible CI.
6+
# As a result, the version needs to be bumped manually at will.
7+
"pybind11==2.9.2",
8+
]
9+
10+
build-backend = "setuptools.build_meta"

test-data/pybind11_mypy_demo/setup.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# pybind11 is available at setup time due to pyproject.toml
2+
from pybind11.setup_helpers import Pybind11Extension
3+
from setuptools import setup
4+
5+
# Documentation: https://pybind11.readthedocs.io/en/stable/compiling.html
6+
ext_modules = [
7+
Pybind11Extension(
8+
"pybind11_mypy_demo",
9+
["src/main.cpp"],
10+
cxx_std=17,
11+
),
12+
]
13+
14+
setup(
15+
name="pybind11-mypy-demo",
16+
version="0.0.1",
17+
ext_modules=ext_modules,
18+
)
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/**
2+
* This file contains the pybind11 reference implementation for the stugen tests,
3+
* and was originally inspired by:
4+
*
5+
* https://github.com/sizmailov/pybind11-mypy-demo
6+
*
7+
* Copyright (c) 2016 The Pybind Development Team, All rights reserved.
8+
*
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice, this
13+
* list of conditions and the following disclaimer.
14+
*
15+
* 2. Redistributions in binary form must reproduce the above copyright notice,
16+
* this list of conditions and the following disclaimer in the documentation
17+
* and/or other materials provided with the distribution.
18+
*
19+
* 3. Neither the name of the copyright holder nor the names of its contributors
20+
* may be used to endorse or promote products derived from this software
21+
* without specific prior written permission.
22+
*
23+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33+
*
34+
* You are under no obligation whatsoever to provide any bug fixes, patches, or
35+
* upgrades to the features, functionality or performance of the source code
36+
* ("Enhancements") to anyone; however, if you choose to make your Enhancements
37+
* available either publicly, or directly to the author of this software, without
38+
* imposing a separate written license agreement for such Enhancements, then you
39+
* hereby grant the following license: a non-exclusive, royalty-free perpetual
40+
* license to install, use, modify, prepare derivative works, incorporate into
41+
* other computer software, distribute, and sublicense such enhancements or
42+
* derivative works thereof, in binary and source code form.
43+
*/
44+
45+
#include <cmath>
46+
#include <pybind11/pybind11.h>
47+
48+
namespace py = pybind11;
49+
50+
namespace basics {
51+
52+
int answer() {
53+
return 42;
54+
}
55+
56+
int sum(int a, int b) {
57+
return a + b;
58+
}
59+
60+
double midpoint(double left, double right){
61+
return left + (right - left)/2;
62+
}
63+
64+
double weighted_midpoint(double left, double right, double alpha=0.5) {
65+
return left + (right - left) * alpha;
66+
}
67+
68+
struct Point {
69+
70+
enum class LengthUnit {
71+
mm=0,
72+
pixel,
73+
inch
74+
};
75+
76+
enum class AngleUnit {
77+
radian=0,
78+
degree
79+
};
80+
81+
Point() : Point(0, 0) {}
82+
Point(double x, double y) : x(x), y(y) {}
83+
84+
static const Point origin;
85+
static const Point x_axis;
86+
static const Point y_axis;
87+
88+
static LengthUnit length_unit;
89+
static AngleUnit angle_unit;
90+
91+
double length() const {
92+
return std::sqrt(x * x + y * y);
93+
}
94+
95+
double distance_to(double other_x, double other_y) const {
96+
double dx = x - other_x;
97+
double dy = y - other_y;
98+
return std::sqrt(dx*dx + dy*dy);
99+
}
100+
101+
double distance_to(const Point& other) const {
102+
return distance_to(other.x, other.y);
103+
}
104+
105+
double x, y;
106+
};
107+
108+
const Point Point::origin = Point(0, 0);
109+
const Point Point::x_axis = Point(1, 0);
110+
const Point Point::y_axis = Point(0, 1);
111+
112+
Point::LengthUnit Point::length_unit = Point::LengthUnit::mm;
113+
Point::AngleUnit Point::angle_unit = Point::AngleUnit::radian;
114+
115+
} // namespace: basics
116+
117+
void bind_basics(py::module& basics) {
118+
119+
using namespace basics;
120+
121+
// Functions
122+
basics.def("answer", &answer);
123+
basics.def("sum", &sum);
124+
basics.def("midpoint", &midpoint, py::arg("left"), py::arg("right"));
125+
basics.def("weighted_midpoint", weighted_midpoint, py::arg("left"), py::arg("right"), py::arg("alpha")=0.5);
126+
127+
// Classes
128+
py::class_<Point> pyPoint(basics, "Point");
129+
py::enum_<Point::LengthUnit> pyLengthUnit(pyPoint, "LengthUnit");
130+
py::enum_<Point::AngleUnit> pyAngleUnit(pyPoint, "AngleUnit");
131+
132+
pyPoint
133+
.def(py::init<>())
134+
.def(py::init<double, double>(), py::arg("x"), py::arg("y"))
135+
.def("distance_to", py::overload_cast<double, double>(&Point::distance_to, py::const_), py::arg("x"), py::arg("y"))
136+
.def("distance_to", py::overload_cast<const Point&>(&Point::distance_to, py::const_), py::arg("other"))
137+
.def_readwrite("x", &Point::x)
138+
.def_property("y",
139+
[](Point& self){ return self.y; },
140+
[](Point& self, double value){ self.y = value; }
141+
)
142+
.def_property_readonly("length", &Point::length)
143+
.def_property_readonly_static("x_axis", [](py::object cls){return Point::x_axis;})
144+
.def_property_readonly_static("y_axis", [](py::object cls){return Point::y_axis;})
145+
.def_readwrite_static("length_unit", &Point::length_unit)
146+
.def_property_static("angle_unit",
147+
[](py::object& /*cls*/){ return Point::angle_unit; },
148+
[](py::object& /*cls*/, Point::AngleUnit value){ Point::angle_unit = value; }
149+
);
150+
151+
pyPoint.attr("origin") = Point::origin;
152+
153+
pyLengthUnit
154+
.value("mm", Point::LengthUnit::mm)
155+
.value("pixel", Point::LengthUnit::pixel)
156+
.value("inch", Point::LengthUnit::inch);
157+
158+
pyAngleUnit
159+
.value("radian", Point::AngleUnit::radian)
160+
.value("degree", Point::AngleUnit::degree);
161+
162+
// Module-level attributes
163+
basics.attr("PI") = std::acos(-1);
164+
basics.attr("__version__") = "0.0.1";
165+
}
166+
167+
PYBIND11_MODULE(pybind11_mypy_demo, m) {
168+
auto basics = m.def_submodule("basics");
169+
bind_basics(basics);
170+
}

test-data/stubgen/pybind11_mypy_demo/basics.pyi renamed to test-data/pybind11_mypy_demo/stubgen/pybind11_mypy_demo/basics.pyi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class Point:
1818
def __setstate__(self, state: int) -> None: ...
1919
@property
2020
def name(self) -> str: ...
21+
@property
22+
def value(self) -> int: ...
2123

2224
class LengthUnit:
2325
__entries: ClassVar[dict] = ...
@@ -34,6 +36,8 @@ class Point:
3436
def __setstate__(self, state: int) -> None: ...
3537
@property
3638
def name(self) -> str: ...
39+
@property
40+
def value(self) -> int: ...
3741
angle_unit: ClassVar[Point.AngleUnit] = ...
3842
length_unit: ClassVar[Point.LengthUnit] = ...
3943
x_axis: ClassVar[Point] = ... # read-only

0 commit comments

Comments
 (0)