Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Pybind11 cleanup #28857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ jobs:
# Preinstall build requirements to enable no-build-isolation builds.
python -m pip install --upgrade $PRE \
'contourpy>=1.0.1' cycler fonttools kiwisolver importlib_resources \
numpy packaging pillow 'pyparsing!=3.1.0' python-dateutil setuptools-scm \
packaging pillow 'pyparsing!=3.1.0' python-dateutil setuptools-scm \
'meson-python>=0.13.1' 'pybind11>=2.6' \
-r requirements/testing/all.txt \
${{ matrix.extra-requirements }}
Expand Down
13 changes: 0 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ requires-python = ">=3.10"
# Should be a copy of the build dependencies below.
dev = [
"meson-python>=0.13.1",
"numpy>=1.25",
"pybind11>=2.6,!=2.13.3",
"setuptools_scm>=7",
# Not required by us but setuptools_scm without a version, cso _if_
Expand All @@ -74,18 +73,6 @@ requires = [
"meson-python>=0.13.1",
"pybind11>=2.6,!=2.13.3",
"setuptools_scm>=7",

# Comments on numpy build requirement range:
#
# 1. >=2.0.x is the numpy requirement for wheel builds for distribution
# on PyPI - building against 2.x yields wheels that are also
# ABI-compatible with numpy 1.x at runtime.
# 2. Note that building against numpy 1.x works fine too - users and
# redistributors can do this by installing the numpy version they like
# and disabling build isolation.
# 3. The <2.3 upper bound is for matching the numpy deprecation policy,
# it should not be loosened.
"numpy>=2.0.0rc1,<2.3",
]

[tool.meson-python.args]
Expand Down
1 change: 0 additions & 1 deletion requirements/dev/build-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pybind11!=2.13.3
meson-python
numpy<2.1.0
setuptools-scm
1 change: 0 additions & 1 deletion requirements/testing/mypy.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ contourpy>=1.0.1
cycler>=0.10
fonttools>=4.22.0
kiwisolver>=1.3.1
numpy>=1.19
packaging>=20.0
pillow>=8
pyparsing>=2.3.1
Expand Down
8 changes: 4 additions & 4 deletions src/_backend_agg.h
Original file line number Diff line number Diff line change
Expand Up @@ -1234,11 +1234,11 @@ inline void RendererAgg::draw_gouraud_triangles(GCAgg &gc,
ColorArray &colors,
agg::trans_affine &trans)
{
if (points.shape(0) && !check_trailing_shape(points, "points", 3, 2)) {
throw py::error_already_set();
if (points.shape(0)) {
check_trailing_shape(points, "points", 3, 2);
}
if (colors.shape(0) && !check_trailing_shape(colors, "colors", 3, 4)) {
throw py::error_already_set();
if (colors.shape(0)) {
check_trailing_shape(colors, "colors", 3, 4);
}
if (points.shape(0) != colors.shape(0)) {
throw py::value_error(
Expand Down
10 changes: 0 additions & 10 deletions src/_backend_agg_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include "mplutils.h"
#include "numpy_cpp.h"
#include "py_converters.h"
#include "_backend_agg.h"
#include "py_converters_11.h"

namespace py = pybind11;
using namespace pybind11::literals;
Expand Down Expand Up @@ -189,14 +187,6 @@ PyRendererAgg_draw_gouraud_triangles(RendererAgg *self,

PYBIND11_MODULE(_backend_agg, m)
{
auto ia = [m]() -> const void* {
import_array();
return &m;
};
if (ia() == NULL) {
throw py::error_already_set();
}

py::class_<RendererAgg>(m, "RendererAgg", py::buffer_protocol())
.def(py::init<unsigned int, unsigned int, double>(),
"width"_a, "height"_a, "dpi"_a)
Expand Down
2 changes: 1 addition & 1 deletion src/_image_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <pybind11/numpy.h>

#include "_image_resample.h"
#include "py_converters_11.h"
#include "py_converters.h"

namespace py = pybind11;
using namespace pybind11::literals;
Expand Down
5 changes: 2 additions & 3 deletions src/_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

#include "path_converters.h"
#include "_backend_agg_basic_types.h"
#include "numpy_cpp.h"

const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3 };

Expand Down Expand Up @@ -1004,15 +1003,15 @@ void convert_path_to_polygons(PathIterator &path,

template <class VertexSource>
void
__cleanup_path(VertexSource &source, std::vector<double> &vertices, std::vector<npy_uint8> &codes)
__cleanup_path(VertexSource &source, std::vector<double> &vertices, std::vector<uint8_t> &codes)
{
unsigned code;
double x, y;
do {
code = source.vertex(&x, &y);
vertices.push_back(x);
vertices.push_back(y);
codes.push_back((npy_uint8)code);
codes.push_back(static_cast<uint8_t>(code));
} while (code != agg::path_cmd_stop);
}

Expand Down
17 changes: 2 additions & 15 deletions src/_path_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
#include <string>
#include <vector>

#include "numpy_cpp.h"

#include "_path.h"

#include "_backend_agg_basic_types.h"
#include "py_adaptors.h"
#include "py_converters.h"
#include "py_converters_11.h"

namespace py = pybind11;
using namespace pybind11::literals;
Expand Down Expand Up @@ -184,9 +181,7 @@ Py_affine_transform(py::array_t<double, py::array::c_style | py::array::forcecas
if (vertices_arr.ndim() == 2) {
auto vertices = vertices_arr.unchecked<2>();

if(!check_trailing_shape(vertices, "vertices", 2)) {
throw py::error_already_set();
}
check_trailing_shape(vertices, "vertices", 2);

py::ssize_t dims[] = { vertices.shape(0), 2 };
py::array_t<double> result(dims);
Expand Down Expand Up @@ -267,7 +262,7 @@ Py_cleanup_path(mpl::PathIterator path, agg::trans_affine trans, bool remove_nan
bool do_clip = (clip_rect.x1 < clip_rect.x2 && clip_rect.y1 < clip_rect.y2);

std::vector<double> vertices;
std::vector<npy_uint8> codes;
std::vector<uint8_t> codes;

cleanup_path(path, trans, remove_nans, do_clip, clip_rect, snap_mode, stroke_width,
*simplify, return_curves, sketch, vertices, codes);
Expand Down Expand Up @@ -375,14 +370,6 @@ Py_is_sorted_and_has_non_nan(py::object obj)

PYBIND11_MODULE(_path, m)
{
auto ia = [m]() -> const void* {
import_array();
return &m;
};
if (ia() == NULL) {
throw py::error_already_set();
}

m.def("point_in_path", &Py_point_in_path,
"x"_a, "y"_a, "radius"_a, "path"_a, "trans"_a);
m.def("points_in_path", &Py_points_in_path,
Expand Down
9 changes: 0 additions & 9 deletions src/ft2font_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <pybind11/stl.h>

#include "ft2font.h"
#include "numpy/arrayobject.h"

#include <set>
#include <sstream>
Expand Down Expand Up @@ -955,14 +954,6 @@ PyFT2Font_fname(PyFT2Font *self)

PYBIND11_MODULE(ft2font, m)
{
auto ia = [m]() -> const void* {
import_array();
return &m;
};
if (ia() == NULL) {
throw py::error_already_set();
}

if (FT_Init_FreeType(&_ft2Library)) { // initialize library
throw std::runtime_error("Could not initialize the freetype2 library");
}
Expand Down
63 changes: 5 additions & 58 deletions src/meson.build
Original file line number Diff line number Diff line change
@@ -1,42 +1,3 @@
# NumPy include directory - needed in all submodules
# The try-except is needed because when things are split across drives on Windows, there
# is no relative path and an exception gets raised. There may be other such cases, so add
# a catch-all and switch to an absolute path. Relative paths are needed when for example
# a virtualenv is placed inside the source tree; Meson rejects absolute paths to places
# inside the source tree.
# For cross-compilation it is often not possible to run the Python interpreter in order
# to retrieve numpy's include directory. It can be specified in the cross file instead:
#
# [properties]
# numpy-include-dir = /abspath/to/host-pythons/site-packages/numpy/core/include
#
# This uses the path as is, and avoids running the interpreter.
incdir_numpy = meson.get_external_property('numpy-include-dir', 'not-given')
if incdir_numpy == 'not-given'
incdir_numpy = run_command(py3,
[
'-c',
'''import os
import numpy as np
try:
incdir = os.path.relpath(np.get_include())
except Exception:
incdir = np.get_include()
print(incdir)'''
],
check: true
).stdout().strip()
endif
numpy_dep = declare_dependency(
compile_args: [
'-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION',
# Allow NumPy's printf format specifiers in C++.
'-D__STDC_FORMAT_MACROS=1',
],
include_directories: include_directories(incdir_numpy),
dependencies: py3_dep,
)

# For cross-compilation it is often not possible to run the Python interpreter in order
# to retrieve the platform-specific /dev/null. It can be specified in the cross file
# instead:
Expand Down Expand Up @@ -73,12 +34,10 @@ extension_data = {
'_backend_agg': {
'subdir': 'matplotlib/backends',
'sources': files(
'py_converters.cpp',
'py_converters_11.cpp',
'_backend_agg.cpp',
'_backend_agg_wrapper.cpp',
),
'dependencies': [agg_dep, numpy_dep, freetype_dep, pybind11_dep],
'dependencies': [agg_dep, freetype_dep, pybind11_dep],
},
'_c_internal_utils': {
'subdir': 'matplotlib',
Expand All @@ -92,10 +51,9 @@ extension_data = {
'sources': files(
'ft2font.cpp',
'ft2font_wrapper.cpp',
'py_converters.cpp',
),
'dependencies': [
freetype_dep, pybind11_dep, numpy_dep, agg_dep.partial_dependency(includes: true),
freetype_dep, pybind11_dep, agg_dep.partial_dependency(includes: true),
],
'cpp_args': [
'-DFREETYPE_BUILD_TYPE="@0@"'.format(
Expand All @@ -107,7 +65,7 @@ extension_data = {
'subdir': 'matplotlib',
'sources': files(
'_image_wrapper.cpp',
'py_converters_11.cpp',
'py_converters.cpp',
),
'dependencies': [
pybind11_dep,
Expand All @@ -118,11 +76,9 @@ extension_data = {
'_path': {
'subdir': 'matplotlib',
'sources': files(
'py_converters.cpp',
'py_converters_11.cpp',
'_path_wrapper.cpp',
),
'dependencies': [numpy_dep, agg_dep, pybind11_dep],
'dependencies': [agg_dep, pybind11_dep],
},
'_qhull': {
'subdir': 'matplotlib',
Expand Down Expand Up @@ -162,16 +118,7 @@ extension_data = {
}

foreach ext, kwargs : extension_data
# Ensure that PY_ARRAY_UNIQUE_SYMBOL is uniquely defined for each extension.
unique_array_api = '-DPY_ARRAY_UNIQUE_SYMBOL=MPL_@0@_ARRAY_API'.format(ext.replace('.', '_'))
additions = {
'c_args': [unique_array_api] + kwargs.get('c_args', []),
'cpp_args': [unique_array_api] + kwargs.get('cpp_args', []),
}
py3.extension_module(
ext,
install: true,
kwargs: kwargs + additions)
py3.extension_module(ext, install: true, kwargs: kwargs)
endforeach

if get_option('macosx') and host_machine.system() == 'darwin'
Expand Down
53 changes: 15 additions & 38 deletions src/mplutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,74 +48,51 @@
CLOSEPOLY = 0x4f
};

inline int prepare_and_add_type(PyTypeObject *type, PyObject *module)
{
if (PyType_Ready(type)) {
return -1;
}
char const* ptr = strrchr(type->tp_name, '.');
if (!ptr) {
PyErr_SetString(PyExc_ValueError, "tp_name should be a qualified name");
return -1;
}
if (PyModule_AddObject(module, ptr + 1, (PyObject *)type)) {
return -1;
}
return 0;
}

#ifdef __cplusplus // not for macosx.m
// Check that array has shape (N, d1) or (N, d1, d2). We cast d1, d2 to longs
// so that we don't need to access the NPY_INTP_FMT macro here.
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;
using namespace pybind11::literals;

template<typename T>
inline bool check_trailing_shape(T array, char const* name, long d1)
inline void check_trailing_shape(T array, char const* name, long d1)
{
if (array.ndim() != 2) {
PyErr_Format(PyExc_ValueError,
"Expected 2-dimensional array, got %ld",
array.ndim());
return false;
throw py::value_error(
"Expected 2-dimensional array, got %d"_s.format(array.ndim()));
}
if (array.size() == 0) {
// Sometimes things come through as atleast_2d, etc., but they're empty, so
// don't bother enforcing the trailing shape.
return true;
return;
}
if (array.shape(1) != d1) {
PyErr_Format(PyExc_ValueError,
"%s must have shape (N, %ld), got (%ld, %ld)",
name, d1, array.shape(0), array.shape(1));
return false;
throw py::value_error(
"%s must have shape (N, %d), got (%d, %d)"_s.format(

Check warning on line 74 in src/mplutils.h

View check run for this annotation

Codecov / codecov/patch

src/mplutils.h#L74

Added line #L74 was not covered by tests
name, d1, array.shape(0), array.shape(1)));
}
return true;
}

template<typename T>
inline bool check_trailing_shape(T array, char const* name, long d1, long d2)
inline void check_trailing_shape(T array, char const* name, long d1, long d2)
{
if (array.ndim() != 3) {
PyErr_Format(PyExc_ValueError,
"Expected 3-dimensional array, got %ld",
array.ndim());
return false;
throw py::value_error(
"Expected 3-dimensional array, got %d"_s.format(array.ndim()));
}
if (array.size() == 0) {
// Sometimes things come through as atleast_3d, etc., but they're empty, so
// don't bother enforcing the trailing shape.
return true;
return;
}
if (array.shape(1) != d1 || array.shape(2) != d2) {
PyErr_Format(PyExc_ValueError,
"%s must have shape (N, %ld, %ld), got (%ld, %ld, %ld)",
name, d1, d2, array.shape(0), array.shape(1), array.shape(2));
return false;
throw py::value_error(
"%s must have shape (N, %d, %d), got (%d, %d, %d)"_s.format(

Check warning on line 93 in src/mplutils.h

View check run for this annotation

Codecov / codecov/patch

src/mplutils.h#L93

Added line #L93 was not covered by tests
name, d1, d2, array.shape(0), array.shape(1), array.shape(2)));
}
return true;
}

/* In most cases, code should use safe_first_shape(obj) instead of obj.shape(0), since
Expand Down
Loading
Loading