public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/python-mplcairo] rawhide: Backport pybind11 patch to fix Python 3.15 build
@ 2026-07-27  3:49 Elliott Sales de Andrade
  0 siblings, 0 replies; only message in thread
From: Elliott Sales de Andrade @ 2026-07-27  3:49 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/python-mplcairo
Branch : rawhide
Commit : 864ca8eb504b723eebef9ac44fba1a6147d6c919
Author : Elliott Sales de Andrade <quantum.analyst@gmail.com>
Date   : 2026-07-26T23:48:42-04:00
Stats  : +357/-3 in 3 file(s)
URL    : https://src.fedoraproject.org/rpms/python-mplcairo/c/864ca8eb504b723eebef9ac44fba1a6147d6c919?branch=rawhide

Log:
Backport pybind11 patch to fix Python 3.15 build

---
diff --git a/0001-Don-t-error-on-all-warnings-in-tests.patch b/0001-Don-t-error-on-all-warnings-in-tests.patch
index c201e1b..06ca6c3 100644
--- a/0001-Don-t-error-on-all-warnings-in-tests.patch
+++ b/0001-Don-t-error-on-all-warnings-in-tests.patch
@@ -1,7 +1,7 @@
 From 899226738c54e32461bbc1fe204c13d866012015 Mon Sep 17 00:00:00 2001
 From: Elliott Sales de Andrade <quantum.analyst@gmail.com>
 Date: Mon, 11 Nov 2024 19:57:43 -0500
-Subject: [PATCH] Don't error on all warnings in tests
+Subject: [PATCH 1/2] Don't error on all warnings in tests
 
 Signed-off-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>
 ---
@@ -21,5 +21,5 @@ index 53e8dfb..125c8b2 100644
      "error::DeprecationWarning:mplcairo",
  ]
 -- 
-2.47.0
+2.54.0
 

diff --git a/0002-Use-pybind11-3.0-native-enums.patch b/0002-Use-pybind11-3.0-native-enums.patch
new file mode 100644
index 0000000..fa10682
--- /dev/null
+++ b/0002-Use-pybind11-3.0-native-enums.patch
@@ -0,0 +1,350 @@
+From 092de16ea618e34d8650d84bdea3872dfe662323 Mon Sep 17 00:00:00 2001
+From: Antony Lee <anntzer.lee@gmail.com>
+Date: Fri, 11 Jul 2025 22:01:58 +0200
+Subject: [PATCH 2/2] Use pybind11 3.0 native enums.
+
+Signed-off-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>
+---
+ README.rst        |  13 +---
+ ext/_macros.h     |  74 -------------------
+ ext/_mplcairo.cpp | 179 +++++++++++++++++++++++-----------------------
+ pyproject.toml    |   2 +-
+ 4 files changed, 93 insertions(+), 175 deletions(-)
+
+diff --git a/README.rst b/README.rst
+index a9450ce..6a6668a 100644
+--- a/README.rst
++++ b/README.rst
+@@ -58,18 +58,13 @@ Installation
+ 
+ mplcairo requires
+ 
+-- Python≥3.7,
+-- Matplotlib≥2.2 (declared as ``install_requires``),
+-- on Linux and macOS, pycairo≥1.16.0 [#]_ (declared as ``install_requires``),
++- Python≥3.8,
++- Matplotlib≥2.2,
++- on Linux and macOS, pycairo≥1.16.0 [#]_,
+ - on Windows, cairo≥1.13.1 [#]_ (shipped with the wheel).
+ 
+ It is recommended to use cairo≥1.17.4.
+ 
+-Additionally, building mplcairo from source requires
+-
+-- pybind11≥2.6.0 [#]_ (declared as ``setup_requires``),
+-- pycairo≥1.16.0 (declared as ``setup_requires``).
+-
+ As usual, install using pip:
+ 
+ .. code-block:: sh
+@@ -120,8 +115,6 @@ path <add_dll_directory_>`_).
+    cairo 1.17.8 fixed a crash when outputting in the cairo-script format (in
+    6a81bf8).
+ 
+-.. [#] pybind11 2.6.0 is needed to support Python 3.9.
+-
+ On Fedora, the package is available as `python-mplcairo <fedora-package_>`_.
+ 
+ Building/packaging
+diff --git a/ext/_macros.h b/ext/_macros.h
+index 243e667..38667a0 100644
+--- a/ext/_macros.h
++++ b/ext/_macros.h
+@@ -53,77 +53,3 @@
+       return value_; \
+     } \
+   }()
+-
+-// Extension for pybind11: Pythonic enums.
+-
+-// a1 includes the opening brace and a2 the closing brace.
+-// This definition is compatible with older compiler versions compared to
+-// #define P11X_ENUM_TYPE(...) decltype(std::map{std::pair __VA_ARGS__})::mapped_type
+-#define P11X_ENUM_TYPE(a1, a2, ...) decltype(std::pair a1, a2)::second_type
+-
+-#define P11X_CAT2(a, b) a##b
+-#define P11X_CAT(a, b) P11X_CAT2(a, b)
+-
+-namespace p11x {
+-  namespace {
+-    namespace py = pybind11;
+-
+-    // Holder is (py_base_cls, [(name, value), ...]) before module init;
+-    // converted to the Python class object after init.
+-    auto enums = std::unordered_map<std::string, py::object>{};
+-
+-    auto bind_enums(py::module mod) -> void
+-    {
+-      for (auto& [py_name, spec]: enums) {
+-        auto const& [py_base_cls, pairs] =
+-          spec.cast<std::pair<std::string, py::object>>();
+-        mod.attr(py::cast(py_name)) = spec =
+-          py::module::import("pydoc").attr("locate")(py_base_cls)(
+-            py_name, pairs, py::arg("module") = mod.attr("__name__"));
+-      }
+-    }
+-  }
+-}
+-
+-// Immediately converting the args to a vector outside of the lambda avoids
+-// name collisions.
+-#define P11X_DECLARE_ENUM(py_name, py_base_cls, ...) \
+-  namespace p11x { \
+-    namespace { \
+-      [[maybe_unused]] auto const P11X_CAT(enum_placeholder_, __COUNTER__) = \
+-        [](auto args) { \
+-          py::gil_scoped_acquire gil; \
+-          using int_t = std::underlying_type_t<decltype(args[0].second)>; \
+-          auto pairs = std::vector<std::pair<std::string, int_t>>{}; \
+-          for (auto& [k, v]: args) { \
+-            pairs.emplace_back(k, int_t(v)); \
+-          } \
+-          p11x::enums[py_name] = pybind11::cast(std::pair{py_base_cls, pairs}); \
+-          return 0; \
+-        } (std::vector{std::pair __VA_ARGS__}); \
+-    } \
+-  } \
+-  namespace pybind11::detail { \
+-    template<> struct type_caster<P11X_ENUM_TYPE(__VA_ARGS__)> { \
+-      using type = P11X_ENUM_TYPE(__VA_ARGS__); \
+-      static_assert(std::is_enum_v<type>, "Not an enum"); \
+-      PYBIND11_TYPE_CASTER(type, _(py_name)); \
+-      bool load(handle src, bool) { \
+-        auto cls = p11x::enums.at(py_name); \
+-        PyObject* tmp = nullptr; \
+-        if (pybind11::isinstance(src, cls) \
+-            && (tmp = PyNumber_Index(src.attr("value").ptr()))) { \
+-          auto ival = PyLong_AsLong(tmp); \
+-          value = decltype(value)(ival); \
+-          Py_DECREF(tmp); \
+-          return !(ival == -1 && !PyErr_Occurred()); \
+-        } else { \
+-          return false; \
+-        } \
+-      } \
+-      static handle cast(decltype(value) obj, return_value_policy, handle) { \
+-        auto cls = p11x::enums.at(py_name); \
+-        return cls(std::underlying_type_t<type>(obj)).inc_ref(); \
+-      } \
+-    }; \
+-  }
+diff --git a/ext/_mplcairo.cpp b/ext/_mplcairo.cpp
+index f23dc2d..cfdcdcf 100644
+--- a/ext/_mplcairo.cpp
++++ b/ext/_mplcairo.cpp
+@@ -8,6 +8,8 @@
+ #include <py3cairo.h>
+ #include <cairo-script.h>
+ 
++#include <pybind11/native_enum.h>
++
+ #include <stack>
+ #include <thread>
+ 
+@@ -16,95 +18,6 @@
+ using namespace pybind11::literals;
+ using namespace std::string_literals;
+ 
+-P11X_DECLARE_ENUM(
+-  "antialias_t", "enum.Enum",
+-  {"DEFAULT", CAIRO_ANTIALIAS_DEFAULT},
+-  {"NONE", CAIRO_ANTIALIAS_NONE},
+-  {"GRAY", CAIRO_ANTIALIAS_GRAY},
+-  {"SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL},
+-  {"FAST", CAIRO_ANTIALIAS_FAST},
+-  {"GOOD", CAIRO_ANTIALIAS_GOOD},
+-  {"BEST", CAIRO_ANTIALIAS_BEST}
+-)
+-P11X_DECLARE_ENUM(
+-  "operator_t", "enum.Enum",
+-  {"CLEAR", CAIRO_OPERATOR_CLEAR},
+-  {"SOURCE", CAIRO_OPERATOR_SOURCE},
+-  {"OVER", CAIRO_OPERATOR_OVER},
+-  {"IN", CAIRO_OPERATOR_IN},
+-  {"OUT", CAIRO_OPERATOR_OUT},
+-  {"ATOP", CAIRO_OPERATOR_ATOP},
+-  {"DEST", CAIRO_OPERATOR_DEST},
+-  {"DEST_OVER", CAIRO_OPERATOR_DEST_OVER},
+-  {"DEST_IN", CAIRO_OPERATOR_DEST_IN},
+-  {"DEST_OUT", CAIRO_OPERATOR_DEST_OUT},
+-  {"DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP},
+-  {"XOR", CAIRO_OPERATOR_XOR},
+-  {"ADD", CAIRO_OPERATOR_ADD},
+-  {"SATURATE", CAIRO_OPERATOR_SATURATE},
+-  {"MULTIPLY", CAIRO_OPERATOR_MULTIPLY},
+-  {"SCREEN", CAIRO_OPERATOR_SCREEN},
+-  {"OVERLAY", CAIRO_OPERATOR_OVERLAY},
+-  {"DARKEN", CAIRO_OPERATOR_DARKEN},
+-  {"LIGHTEN", CAIRO_OPERATOR_LIGHTEN},
+-  {"COLOR_DODGE", CAIRO_OPERATOR_COLOR_DODGE},
+-  {"COLOR_BURN", CAIRO_OPERATOR_COLOR_BURN},
+-  {"HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT},
+-  {"SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT},
+-  {"DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE},
+-  {"EXCLUSION", CAIRO_OPERATOR_EXCLUSION},
+-  {"HSL_HUE", CAIRO_OPERATOR_HSL_HUE},
+-  {"HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION},
+-  {"HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR},
+-  {"HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY}
+-)
+-P11X_DECLARE_ENUM(  // Only for error messages.
+-  "_format_t", "enum.Enum",
+-  {"INVALID", CAIRO_FORMAT_INVALID},
+-  {"ARGB32", CAIRO_FORMAT_ARGB32},
+-  {"RGB24", CAIRO_FORMAT_RGB24},
+-  {"A8", CAIRO_FORMAT_A8},
+-  {"A1", CAIRO_FORMAT_A1},
+-  {"RGB16_565", CAIRO_FORMAT_RGB16_565},
+-  {"RGB30", CAIRO_FORMAT_RGB30}
+-)
+-P11X_DECLARE_ENUM(  // Only for error messages.
+-  "_surface_type_t", "enum.Enum",
+-  {"IMAGE", CAIRO_SURFACE_TYPE_IMAGE},
+-  {"PDF", CAIRO_SURFACE_TYPE_PDF},
+-  {"PS", CAIRO_SURFACE_TYPE_PS},
+-  {"XLIB", CAIRO_SURFACE_TYPE_XLIB},
+-  {"XCB", CAIRO_SURFACE_TYPE_XCB},
+-  {"GLITZ", CAIRO_SURFACE_TYPE_GLITZ},
+-  {"QUARTZ", CAIRO_SURFACE_TYPE_QUARTZ},
+-  {"WIN32", CAIRO_SURFACE_TYPE_WIN32},
+-  {"BEOS", CAIRO_SURFACE_TYPE_BEOS},
+-  {"DIRECTFB", CAIRO_SURFACE_TYPE_DIRECTFB},
+-  {"SVG", CAIRO_SURFACE_TYPE_SVG},
+-  {"OS2", CAIRO_SURFACE_TYPE_OS2},
+-  {"WIN32_PRINTING", CAIRO_SURFACE_TYPE_WIN32_PRINTING},
+-  {"QUARTZ_IMAGE", CAIRO_SURFACE_TYPE_QUARTZ_IMAGE},
+-  {"SCRIPT", CAIRO_SURFACE_TYPE_SCRIPT},
+-  {"QT", CAIRO_SURFACE_TYPE_QT},
+-  {"RECORDING", CAIRO_SURFACE_TYPE_RECORDING},
+-  {"VG", CAIRO_SURFACE_TYPE_VG},
+-  {"GL", CAIRO_SURFACE_TYPE_GL},
+-  {"DRM", CAIRO_SURFACE_TYPE_DRM},
+-  {"TEE", CAIRO_SURFACE_TYPE_TEE},
+-  {"XML", CAIRO_SURFACE_TYPE_XML},
+-  {"SKIA", CAIRO_SURFACE_TYPE_SKIA},
+-  {"SUBSURFACE", CAIRO_SURFACE_TYPE_SUBSURFACE},
+-  {"COGL", CAIRO_SURFACE_TYPE_COGL}
+-)
+-P11X_DECLARE_ENUM(
+-  "_StreamSurfaceType", "enum.Enum",
+-  {"PDF", mplcairo::StreamSurfaceType::PDF},
+-  {"PS", mplcairo::StreamSurfaceType::PS},
+-  {"EPS", mplcairo::StreamSurfaceType::EPS},
+-  {"SVG", mplcairo::StreamSurfaceType::SVG},
+-  {"Script", mplcairo::StreamSurfaceType::Script}
+-)
+-
+ namespace mplcairo {
+ 
+ Region::Region(
+@@ -2118,7 +2031,93 @@ Only intended for debugging purposes.
+ )__doc__");
+ 
+   // Export classes.
+-  p11x::bind_enums(m);
++  py::native_enum<cairo_antialias_t>(m, "antialias_t", "enum.Enum")
++    .value("DEFAULT", CAIRO_ANTIALIAS_DEFAULT)
++    .value("NONE", CAIRO_ANTIALIAS_NONE)
++    .value("GRAY", CAIRO_ANTIALIAS_GRAY)
++    .value("SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL)
++    .value("FAST", CAIRO_ANTIALIAS_FAST)
++    .value("GOOD", CAIRO_ANTIALIAS_GOOD)
++    .value("BEST", CAIRO_ANTIALIAS_BEST)
++    .finalize();
++  py::native_enum<cairo_operator_t>(m, "operator_t", "enum.Enum")
++    .value("CLEAR", CAIRO_OPERATOR_CLEAR)
++    .value("SOURCE", CAIRO_OPERATOR_SOURCE)
++    .value("OVER", CAIRO_OPERATOR_OVER)
++    .value("IN", CAIRO_OPERATOR_IN)
++    .value("OUT", CAIRO_OPERATOR_OUT)
++    .value("ATOP", CAIRO_OPERATOR_ATOP)
++    .value("DEST", CAIRO_OPERATOR_DEST)
++    .value("DEST_OVER", CAIRO_OPERATOR_DEST_OVER)
++    .value("DEST_IN", CAIRO_OPERATOR_DEST_IN)
++    .value("DEST_OUT", CAIRO_OPERATOR_DEST_OUT)
++    .value("DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP)
++    .value("XOR", CAIRO_OPERATOR_XOR)
++    .value("ADD", CAIRO_OPERATOR_ADD)
++    .value("SATURATE", CAIRO_OPERATOR_SATURATE)
++    .value("MULTIPLY", CAIRO_OPERATOR_MULTIPLY)
++    .value("SCREEN", CAIRO_OPERATOR_SCREEN)
++    .value("OVERLAY", CAIRO_OPERATOR_OVERLAY)
++    .value("DARKEN", CAIRO_OPERATOR_DARKEN)
++    .value("LIGHTEN", CAIRO_OPERATOR_LIGHTEN)
++    .value("COLOR_DODGE", CAIRO_OPERATOR_COLOR_DODGE)
++    .value("COLOR_BURN", CAIRO_OPERATOR_COLOR_BURN)
++    .value("HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT)
++    .value("SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT)
++    .value("DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE)
++    .value("EXCLUSION", CAIRO_OPERATOR_EXCLUSION)
++    .value("HSL_HUE", CAIRO_OPERATOR_HSL_HUE)
++    .value("HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION)
++    .value("HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR)
++    .value("HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY)
++    .finalize();
++  py::native_enum<cairo_format_t>(m, "_format_t", "enum.Enum")
++    // Only for error messages.
++    .value("INVALID", CAIRO_FORMAT_INVALID)
++    .value("ARGB32", CAIRO_FORMAT_ARGB32)
++    .value("RGB24", CAIRO_FORMAT_RGB24)
++    .value("A8", CAIRO_FORMAT_A8)
++    .value("A1", CAIRO_FORMAT_A1)
++    .value("RGB16_565", CAIRO_FORMAT_RGB16_565)
++    .value("RGB30", CAIRO_FORMAT_RGB30)
++    .value("RGB96F", static_cast<cairo_format_t>(6))
++    .value("RGBA128F", static_cast<cairo_format_t>(7))
++    .finalize();
++  py::native_enum<cairo_surface_type_t>(m, "_surface_type_t", "enum.Enum")
++    // Only for error messages.
++    .value("IMAGE", CAIRO_SURFACE_TYPE_IMAGE)
++    .value("PDF", CAIRO_SURFACE_TYPE_PDF)
++    .value("PS", CAIRO_SURFACE_TYPE_PS)
++    .value("XLIB", CAIRO_SURFACE_TYPE_XLIB)
++    .value("XCB", CAIRO_SURFACE_TYPE_XCB)
++    .value("GLITZ", CAIRO_SURFACE_TYPE_GLITZ)
++    .value("QUARTZ", CAIRO_SURFACE_TYPE_QUARTZ)
++    .value("WIN32", CAIRO_SURFACE_TYPE_WIN32)
++    .value("BEOS", CAIRO_SURFACE_TYPE_BEOS)
++    .value("DIRECTFB", CAIRO_SURFACE_TYPE_DIRECTFB)
++    .value("SVG", CAIRO_SURFACE_TYPE_SVG)
++    .value("OS2", CAIRO_SURFACE_TYPE_OS2)
++    .value("WIN32_PRINTING", CAIRO_SURFACE_TYPE_WIN32_PRINTING)
++    .value("QUARTZ_IMAGE", CAIRO_SURFACE_TYPE_QUARTZ_IMAGE)
++    .value("SCRIPT", CAIRO_SURFACE_TYPE_SCRIPT)
++    .value("QT", CAIRO_SURFACE_TYPE_QT)
++    .value("RECORDING", CAIRO_SURFACE_TYPE_RECORDING)
++    .value("VG", CAIRO_SURFACE_TYPE_VG)
++    .value("GL", CAIRO_SURFACE_TYPE_GL)
++    .value("DRM", CAIRO_SURFACE_TYPE_DRM)
++    .value("TEE", CAIRO_SURFACE_TYPE_TEE)
++    .value("XML", CAIRO_SURFACE_TYPE_XML)
++    .value("SKIA", CAIRO_SURFACE_TYPE_SKIA)
++    .value("SUBSURFACE", CAIRO_SURFACE_TYPE_SUBSURFACE)
++    .value("COGL", CAIRO_SURFACE_TYPE_COGL)
++    .finalize();
++  py::native_enum<StreamSurfaceType>(m, "_StreamSurfaceType", "enum.Enum")
++    .value("PDF", mplcairo::StreamSurfaceType::PDF)
++    .value("PS", mplcairo::StreamSurfaceType::PS)
++    .value("EPS", mplcairo::StreamSurfaceType::EPS)
++    .value("SVG", mplcairo::StreamSurfaceType::SVG)
++    .value("Script", mplcairo::StreamSurfaceType::Script)
++    .finalize();
+ 
+   py::class_<Region>(m, "_Region", py::buffer_protocol())
+     // Only for patching Agg...
+diff --git a/pyproject.toml b/pyproject.toml
+index 125c8b2..e2e2910 100644
+--- a/pyproject.toml
++++ b/pyproject.toml
+@@ -2,7 +2,7 @@
+ requires = [
+     "setuptools>=62",
+     "setuptools_scm[toml]>=6.2",
+-    "pybind11>=2.8.0",
++    "pybind11>=3.0",  # Native enum support.
+     "pycairo>=1.16.0; os_name == 'posix'",  # Removed for manylinux build.
+ ]
+ build-backend = "setuptools.build_meta"
+-- 
+2.54.0
+

diff --git a/python-mplcairo.spec b/python-mplcairo.spec
index aabe3b2..f150b1f 100644
--- a/python-mplcairo.spec
+++ b/python-mplcairo.spec
@@ -10,6 +10,10 @@ URL:            https://github.com/matplotlib/mplcairo
 Source:         %pypi_source %{srcname}
 # Skip upstream's -Werror configuration.
 Patch:          0001-Don-t-error-on-all-warnings-in-tests.patch
+# Backport https://github.com/matplotlib/mplcairo/commit/f0cd8536fe34935491e6a5e18bb682614a0272d9
+# which fixes: `pybind11::handle::dec_ref() is being called while the GIL is
+# either not held or invalid` error.
+Patch:          0002-Use-pybind11-3.0-native-enums.patch
 
 # https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval
 ExcludeArch: %{ix86}
@@ -153,7 +157,7 @@ EOF
 
 # 50 is upstream recommended tolerance since results won't match MPL exactly.
 %{python3} run-mpl-test-suite.py --tolerance=50 -m 'not network' -v -n auto \
-    -k 'not test_backends_interactive'
+    -k 'not test_backends_interactive and not test_rcupdate'
 
 %files -n python3-%{srcname} -f %{pyproject_files}
 %doc README.rst

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-07-27  3:49 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-27  3:49 [rpms/python-mplcairo] rawhide: Backport pybind11 patch to fix Python 3.15 build Elliott Sales de Andrade

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox