Dtype field ordering for NumPy 1.14 (#1837)

* Test dtype field order in numpy dtype tests

When running tests with NumPy 1.14 or later this test exposes the
"invalid buffer descriptor" error reported in #1274.

* Create dtype_ptr with ordered fields
This commit is contained in:
Igor Socec 2019-07-15 12:31:03 +01:00 committed by Wenzel Jakob
parent 74d335a535
commit a301c5add8
2 changed files with 15 additions and 4 deletions

View File

@ -1066,8 +1066,14 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
if (numpy_internals.get_type_info(tinfo, false))
pybind11_fail("NumPy: dtype is already registered");
// Use ordered fields because order matters as of NumPy 1.14:
// https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays
std::vector<field_descriptor> ordered_fields(std::move(fields));
std::sort(ordered_fields.begin(), ordered_fields.end(),
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
list names, formats, offsets;
for (auto field : *fields) {
for (auto& field : ordered_fields) {
if (!field.descr)
pybind11_fail(std::string("NumPy: unsupported field dtype: `") +
field.name + "` @ " + tinfo.name());
@ -1084,9 +1090,6 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
// - https://github.com/numpy/numpy/pull/7798
// Because of this, we won't use numpy's logic to generate buffer format
// strings and will just do it ourselves.
std::vector<field_descriptor> ordered_fields(std::move(fields));
std::sort(ordered_fields.begin(), ordered_fields.end(),
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
ssize_t offset = 0;
std::ostringstream oss;
// mark the structure as unaligned with '^', because numpy and C++ don't

View File

@ -29,6 +29,13 @@ std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) {
return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
}
struct SimpleStructReordered {
bool bool_;
float float_;
uint32_t uint_;
long double ldbl_;
};
PYBIND11_PACKED(struct PackedStruct {
bool bool_;
uint32_t uint_;
@ -255,6 +262,7 @@ TEST_SUBMODULE(numpy_dtypes, m) {
py::class_<SimpleStruct>(m, "SimpleStruct");
PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_);
PYBIND11_NUMPY_DTYPE(SimpleStructReordered, bool_, uint_, float_, ldbl_);
PYBIND11_NUMPY_DTYPE(PackedStruct, bool_, uint_, float_, ldbl_);
PYBIND11_NUMPY_DTYPE(NestedStruct, a, b);
PYBIND11_NUMPY_DTYPE(PartialStruct, bool_, uint_, float_, ldbl_);