Skip to content

Commit 7949fd9

Browse files
committed
Use pybind11 3.0 native enums.
1 parent a825f88 commit 7949fd9

File tree

4 files changed

+102
-181
lines changed

4 files changed

+102
-181
lines changed

README.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,17 @@ Installation
5858

5959
mplcairo requires
6060

61-
- Python≥3.7,
62-
- Matplotlib≥2.2 (declared as ``install_requires``),
63-
- on Linux and macOS, pycairo≥1.16.0 [#]_ (declared as ``install_requires``),
61+
- Python≥3.8,
62+
- Matplotlib≥2.2,
63+
- on Linux and macOS, pycairo≥1.16.0 [#]_,
6464
- on Windows, cairo≥1.13.1 [#]_ (shipped with the wheel).
6565

6666
It is recommended to use cairo≥1.17.4.
6767

6868
Additionally, building mplcairo from source requires
6969

70-
- pybind11≥2.6.0 [#]_ (declared as ``setup_requires``),
71-
- pycairo≥1.16.0 (declared as ``setup_requires``).
70+
- pybind11≥3.0 [#]_,
71+
- pycairo≥1.16.0.
7272

7373
As usual, install using pip:
7474

@@ -120,7 +120,7 @@ path <add_dll_directory_>`_).
120120
cairo 1.17.8 fixed a crash when outputting in the cairo-script format (in
121121
6a81bf8).
122122
123-
.. [#] pybind11 2.6.0 is needed to support Python 3.9.
123+
.. [#] pybind11 3.0 supports native enums.
124124
125125
On Fedora, the package is available as `python-mplcairo <fedora-package_>`_.
126126

ext/_macros.h

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -53,77 +53,3 @@
5353
return value_; \
5454
} \
5555
}()
56-
57-
// Extension for pybind11: Pythonic enums.
58-
59-
// a1 includes the opening brace and a2 the closing brace.
60-
// This definition is compatible with older compiler versions compared to
61-
// #define P11X_ENUM_TYPE(...) decltype(std::map{std::pair __VA_ARGS__})::mapped_type
62-
#define P11X_ENUM_TYPE(a1, a2, ...) decltype(std::pair a1, a2)::second_type
63-
64-
#define P11X_CAT2(a, b) a##b
65-
#define P11X_CAT(a, b) P11X_CAT2(a, b)
66-
67-
namespace p11x {
68-
namespace {
69-
namespace py = pybind11;
70-
71-
// Holder is (py_base_cls, [(name, value), ...]) before module init;
72-
// converted to the Python class object after init.
73-
auto enums = std::unordered_map<std::string, py::object>{};
74-
75-
auto bind_enums(py::module mod) -> void
76-
{
77-
for (auto& [py_name, spec]: enums) {
78-
auto const& [py_base_cls, pairs] =
79-
spec.cast<std::pair<std::string, py::object>>();
80-
mod.attr(py::cast(py_name)) = spec =
81-
py::module::import("pydoc").attr("locate")(py_base_cls)(
82-
py_name, pairs, py::arg("module") = mod.attr("__name__"));
83-
}
84-
}
85-
}
86-
}
87-
88-
// Immediately converting the args to a vector outside of the lambda avoids
89-
// name collisions.
90-
#define P11X_DECLARE_ENUM(py_name, py_base_cls, ...) \
91-
namespace p11x { \
92-
namespace { \
93-
[[maybe_unused]] auto const P11X_CAT(enum_placeholder_, __COUNTER__) = \
94-
[](auto args) { \
95-
py::gil_scoped_acquire gil; \
96-
using int_t = std::underlying_type_t<decltype(args[0].second)>; \
97-
auto pairs = std::vector<std::pair<std::string, int_t>>{}; \
98-
for (auto& [k, v]: args) { \
99-
pairs.emplace_back(k, int_t(v)); \
100-
} \
101-
p11x::enums[py_name] = pybind11::cast(std::pair{py_base_cls, pairs}); \
102-
return 0; \
103-
} (std::vector{std::pair __VA_ARGS__}); \
104-
} \
105-
} \
106-
namespace pybind11::detail { \
107-
template<> struct type_caster<P11X_ENUM_TYPE(__VA_ARGS__)> { \
108-
using type = P11X_ENUM_TYPE(__VA_ARGS__); \
109-
static_assert(std::is_enum_v<type>, "Not an enum"); \
110-
PYBIND11_TYPE_CASTER(type, _(py_name)); \
111-
bool load(handle src, bool) { \
112-
auto cls = p11x::enums.at(py_name); \
113-
PyObject* tmp = nullptr; \
114-
if (pybind11::isinstance(src, cls) \
115-
&& (tmp = PyNumber_Index(src.attr("value").ptr()))) { \
116-
auto ival = PyLong_AsLong(tmp); \
117-
value = decltype(value)(ival); \
118-
Py_DECREF(tmp); \
119-
return !(ival == -1 && !PyErr_Occurred()); \
120-
} else { \
121-
return false; \
122-
} \
123-
} \
124-
static handle cast(decltype(value) obj, return_value_policy, handle) { \
125-
auto cls = p11x::enums.at(py_name); \
126-
return cls(std::underlying_type_t<type>(obj)).inc_ref(); \
127-
} \
128-
}; \
129-
}

ext/_mplcairo.cpp

Lines changed: 95 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <py3cairo.h>
99
#include <cairo-script.h>
1010

11+
#include <pybind11/native_enum.h>
12+
1113
#include <stack>
1214
#include <thread>
1315

@@ -16,105 +18,6 @@
1618
using namespace pybind11::literals;
1719
using namespace std::string_literals;
1820

19-
P11X_DECLARE_ENUM(
20-
"antialias_t", "enum.Enum",
21-
{"DEFAULT", CAIRO_ANTIALIAS_DEFAULT},
22-
{"NONE", CAIRO_ANTIALIAS_NONE},
23-
{"GRAY", CAIRO_ANTIALIAS_GRAY},
24-
{"SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL},
25-
{"FAST", CAIRO_ANTIALIAS_FAST},
26-
{"GOOD", CAIRO_ANTIALIAS_GOOD},
27-
{"BEST", CAIRO_ANTIALIAS_BEST}
28-
)
29-
P11X_DECLARE_ENUM(
30-
"dither_t", "enum.Enum",
31-
{"NONE", mplcairo::detail::CAIRO_DITHER_NONE},
32-
{"DEFAULT", mplcairo::detail::CAIRO_DITHER_DEFAULT},
33-
{"FAST", mplcairo::detail::CAIRO_DITHER_FAST},
34-
{"GOOD", mplcairo::detail::CAIRO_DITHER_GOOD},
35-
{"BEST", mplcairo::detail::CAIRO_DITHER_BEST},
36-
)
37-
P11X_DECLARE_ENUM(
38-
"operator_t", "enum.Enum",
39-
{"CLEAR", CAIRO_OPERATOR_CLEAR},
40-
{"SOURCE", CAIRO_OPERATOR_SOURCE},
41-
{"OVER", CAIRO_OPERATOR_OVER},
42-
{"IN", CAIRO_OPERATOR_IN},
43-
{"OUT", CAIRO_OPERATOR_OUT},
44-
{"ATOP", CAIRO_OPERATOR_ATOP},
45-
{"DEST", CAIRO_OPERATOR_DEST},
46-
{"DEST_OVER", CAIRO_OPERATOR_DEST_OVER},
47-
{"DEST_IN", CAIRO_OPERATOR_DEST_IN},
48-
{"DEST_OUT", CAIRO_OPERATOR_DEST_OUT},
49-
{"DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP},
50-
{"XOR", CAIRO_OPERATOR_XOR},
51-
{"ADD", CAIRO_OPERATOR_ADD},
52-
{"SATURATE", CAIRO_OPERATOR_SATURATE},
53-
{"MULTIPLY", CAIRO_OPERATOR_MULTIPLY},
54-
{"SCREEN", CAIRO_OPERATOR_SCREEN},
55-
{"OVERLAY", CAIRO_OPERATOR_OVERLAY},
56-
{"DARKEN", CAIRO_OPERATOR_DARKEN},
57-
{"LIGHTEN", CAIRO_OPERATOR_LIGHTEN},
58-
{"COLOR_DODGE", CAIRO_OPERATOR_COLOR_DODGE},
59-
{"COLOR_BURN", CAIRO_OPERATOR_COLOR_BURN},
60-
{"HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT},
61-
{"SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT},
62-
{"DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE},
63-
{"EXCLUSION", CAIRO_OPERATOR_EXCLUSION},
64-
{"HSL_HUE", CAIRO_OPERATOR_HSL_HUE},
65-
{"HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION},
66-
{"HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR},
67-
{"HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY}
68-
)
69-
P11X_DECLARE_ENUM(
70-
"format_t", "enum.Enum",
71-
{"INVALID", CAIRO_FORMAT_INVALID},
72-
{"ARGB32", CAIRO_FORMAT_ARGB32},
73-
{"RGB24", CAIRO_FORMAT_RGB24},
74-
{"A8", CAIRO_FORMAT_A8},
75-
{"A1", CAIRO_FORMAT_A1},
76-
{"RGB16_565", CAIRO_FORMAT_RGB16_565},
77-
{"RGB30", CAIRO_FORMAT_RGB30},
78-
{"RGB96F", static_cast<cairo_format_t>(6)},
79-
{"RGBA128F", static_cast<cairo_format_t>(7)}
80-
)
81-
P11X_DECLARE_ENUM( // Only for error messages.
82-
"_surface_type_t", "enum.Enum",
83-
{"IMAGE", CAIRO_SURFACE_TYPE_IMAGE},
84-
{"PDF", CAIRO_SURFACE_TYPE_PDF},
85-
{"PS", CAIRO_SURFACE_TYPE_PS},
86-
{"XLIB", CAIRO_SURFACE_TYPE_XLIB},
87-
{"XCB", CAIRO_SURFACE_TYPE_XCB},
88-
{"GLITZ", CAIRO_SURFACE_TYPE_GLITZ},
89-
{"QUARTZ", CAIRO_SURFACE_TYPE_QUARTZ},
90-
{"WIN32", CAIRO_SURFACE_TYPE_WIN32},
91-
{"BEOS", CAIRO_SURFACE_TYPE_BEOS},
92-
{"DIRECTFB", CAIRO_SURFACE_TYPE_DIRECTFB},
93-
{"SVG", CAIRO_SURFACE_TYPE_SVG},
94-
{"OS2", CAIRO_SURFACE_TYPE_OS2},
95-
{"WIN32_PRINTING", CAIRO_SURFACE_TYPE_WIN32_PRINTING},
96-
{"QUARTZ_IMAGE", CAIRO_SURFACE_TYPE_QUARTZ_IMAGE},
97-
{"SCRIPT", CAIRO_SURFACE_TYPE_SCRIPT},
98-
{"QT", CAIRO_SURFACE_TYPE_QT},
99-
{"RECORDING", CAIRO_SURFACE_TYPE_RECORDING},
100-
{"VG", CAIRO_SURFACE_TYPE_VG},
101-
{"GL", CAIRO_SURFACE_TYPE_GL},
102-
{"DRM", CAIRO_SURFACE_TYPE_DRM},
103-
{"TEE", CAIRO_SURFACE_TYPE_TEE},
104-
{"XML", CAIRO_SURFACE_TYPE_XML},
105-
{"SKIA", CAIRO_SURFACE_TYPE_SKIA},
106-
{"SUBSURFACE", CAIRO_SURFACE_TYPE_SUBSURFACE},
107-
{"COGL", CAIRO_SURFACE_TYPE_COGL}
108-
)
109-
P11X_DECLARE_ENUM(
110-
"_StreamSurfaceType", "enum.Enum",
111-
{"PDF", mplcairo::StreamSurfaceType::PDF},
112-
{"PS", mplcairo::StreamSurfaceType::PS},
113-
{"EPS", mplcairo::StreamSurfaceType::EPS},
114-
{"SVG", mplcairo::StreamSurfaceType::SVG},
115-
{"Script", mplcairo::StreamSurfaceType::Script}
116-
)
117-
11821
namespace mplcairo {
11922

12023
Region::Region(
@@ -2134,7 +2037,99 @@ Only intended for debugging purposes.
21342037
)__doc__");
21352038

21362039
// Export classes.
2137-
p11x::bind_enums(m);
2040+
py::native_enum<cairo_antialias_t>(m, "antialias_t", "enum.Enum")
2041+
.value("DEFAULT", CAIRO_ANTIALIAS_DEFAULT)
2042+
.value("NONE", CAIRO_ANTIALIAS_NONE)
2043+
.value("GRAY", CAIRO_ANTIALIAS_GRAY)
2044+
.value("SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL)
2045+
.value("FAST", CAIRO_ANTIALIAS_FAST)
2046+
.value("GOOD", CAIRO_ANTIALIAS_GOOD)
2047+
.value("BEST", CAIRO_ANTIALIAS_BEST)
2048+
.finalize();
2049+
py::native_enum<detail::cairo_dither_t>(m, "dither_t", "enum.Enum")
2050+
.value("NONE", detail::CAIRO_DITHER_NONE)
2051+
.value("DEFAULT", detail::CAIRO_DITHER_DEFAULT)
2052+
.value("FAST", detail::CAIRO_DITHER_FAST)
2053+
.value("GOOD", detail::CAIRO_DITHER_GOOD)
2054+
.value("BEST", detail::CAIRO_DITHER_BEST)
2055+
.finalize();
2056+
py::native_enum<cairo_operator_t>(m, "operator_t", "enum.Enum")
2057+
.value("CLEAR", CAIRO_OPERATOR_CLEAR)
2058+
.value("SOURCE", CAIRO_OPERATOR_SOURCE)
2059+
.value("OVER", CAIRO_OPERATOR_OVER)
2060+
.value("IN", CAIRO_OPERATOR_IN)
2061+
.value("OUT", CAIRO_OPERATOR_OUT)
2062+
.value("ATOP", CAIRO_OPERATOR_ATOP)
2063+
.value("DEST", CAIRO_OPERATOR_DEST)
2064+
.value("DEST_OVER", CAIRO_OPERATOR_DEST_OVER)
2065+
.value("DEST_IN", CAIRO_OPERATOR_DEST_IN)
2066+
.value("DEST_OUT", CAIRO_OPERATOR_DEST_OUT)
2067+
.value("DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP)
2068+
.value("XOR", CAIRO_OPERATOR_XOR)
2069+
.value("ADD", CAIRO_OPERATOR_ADD)
2070+
.value("SATURATE", CAIRO_OPERATOR_SATURATE)
2071+
.value("MULTIPLY", CAIRO_OPERATOR_MULTIPLY)
2072+
.value("SCREEN", CAIRO_OPERATOR_SCREEN)
2073+
.value("OVERLAY", CAIRO_OPERATOR_OVERLAY)
2074+
.value("DARKEN", CAIRO_OPERATOR_DARKEN)
2075+
.value("LIGHTEN", CAIRO_OPERATOR_LIGHTEN)
2076+
.value("COLOR_DODGE", CAIRO_OPERATOR_COLOR_DODGE)
2077+
.value("COLOR_BURN", CAIRO_OPERATOR_COLOR_BURN)
2078+
.value("HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT)
2079+
.value("SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT)
2080+
.value("DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE)
2081+
.value("EXCLUSION", CAIRO_OPERATOR_EXCLUSION)
2082+
.value("HSL_HUE", CAIRO_OPERATOR_HSL_HUE)
2083+
.value("HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION)
2084+
.value("HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR)
2085+
.value("HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY)
2086+
.finalize();
2087+
py::native_enum<cairo_format_t>(m, "format_t", "enum.Enum")
2088+
.value("INVALID", CAIRO_FORMAT_INVALID)
2089+
.value("ARGB32", CAIRO_FORMAT_ARGB32)
2090+
.value("RGB24", CAIRO_FORMAT_RGB24)
2091+
.value("A8", CAIRO_FORMAT_A8)
2092+
.value("A1", CAIRO_FORMAT_A1)
2093+
.value("RGB16_565", CAIRO_FORMAT_RGB16_565)
2094+
.value("RGB30", CAIRO_FORMAT_RGB30)
2095+
.value("RGB96F", static_cast<cairo_format_t>(6))
2096+
.value("RGBA128F", static_cast<cairo_format_t>(7))
2097+
.finalize();
2098+
py::native_enum<cairo_surface_type_t>(m, "_surface_type_t", "enum.Enum")
2099+
// Only for error messages.
2100+
.value("IMAGE", CAIRO_SURFACE_TYPE_IMAGE)
2101+
.value("PDF", CAIRO_SURFACE_TYPE_PDF)
2102+
.value("PS", CAIRO_SURFACE_TYPE_PS)
2103+
.value("XLIB", CAIRO_SURFACE_TYPE_XLIB)
2104+
.value("XCB", CAIRO_SURFACE_TYPE_XCB)
2105+
.value("GLITZ", CAIRO_SURFACE_TYPE_GLITZ)
2106+
.value("QUARTZ", CAIRO_SURFACE_TYPE_QUARTZ)
2107+
.value("WIN32", CAIRO_SURFACE_TYPE_WIN32)
2108+
.value("BEOS", CAIRO_SURFACE_TYPE_BEOS)
2109+
.value("DIRECTFB", CAIRO_SURFACE_TYPE_DIRECTFB)
2110+
.value("SVG", CAIRO_SURFACE_TYPE_SVG)
2111+
.value("OS2", CAIRO_SURFACE_TYPE_OS2)
2112+
.value("WIN32_PRINTING", CAIRO_SURFACE_TYPE_WIN32_PRINTING)
2113+
.value("QUARTZ_IMAGE", CAIRO_SURFACE_TYPE_QUARTZ_IMAGE)
2114+
.value("SCRIPT", CAIRO_SURFACE_TYPE_SCRIPT)
2115+
.value("QT", CAIRO_SURFACE_TYPE_QT)
2116+
.value("RECORDING", CAIRO_SURFACE_TYPE_RECORDING)
2117+
.value("VG", CAIRO_SURFACE_TYPE_VG)
2118+
.value("GL", CAIRO_SURFACE_TYPE_GL)
2119+
.value("DRM", CAIRO_SURFACE_TYPE_DRM)
2120+
.value("TEE", CAIRO_SURFACE_TYPE_TEE)
2121+
.value("XML", CAIRO_SURFACE_TYPE_XML)
2122+
.value("SKIA", CAIRO_SURFACE_TYPE_SKIA)
2123+
.value("SUBSURFACE", CAIRO_SURFACE_TYPE_SUBSURFACE)
2124+
.value("COGL", CAIRO_SURFACE_TYPE_COGL)
2125+
.finalize();
2126+
py::native_enum<StreamSurfaceType>(m, "_StreamSurfaceType", "enum.Enum")
2127+
.value("PDF", mplcairo::StreamSurfaceType::PDF)
2128+
.value("PS", mplcairo::StreamSurfaceType::PS)
2129+
.value("EPS", mplcairo::StreamSurfaceType::EPS)
2130+
.value("SVG", mplcairo::StreamSurfaceType::SVG)
2131+
.value("Script", mplcairo::StreamSurfaceType::Script)
2132+
.finalize();
21382133

21392134
py::class_<Region>(m, "_Region", py::buffer_protocol())
21402135
// Only for patching Agg...

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
requires = [
33
"setuptools>=62",
44
"setuptools_scm[toml]>=6.2",
5-
"pybind11>=2.8.0",
5+
"pybind11>=3.0",
66
"pycairo>=1.16.0; os_name == 'posix'", # Removed for manylinux build.
77
]
88
build-backend = "setuptools.build_meta"

0 commit comments

Comments
 (0)