Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
7 changes: 6 additions & 1 deletion include/pybind11/numpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,11 +507,16 @@ class dtype : public object {
return detail::array_descriptor_proxy(m_ptr)->names != nullptr;
}

/// Single-character type code.
/// Single-character for dtype's kind (ex: float and double are 'f' or int and long int are 'i')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"float and double" could be "floating point types", and "int and long" could be "integral types". But this works as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay !

char kind() const {
return detail::array_descriptor_proxy(m_ptr)->kind;
}

/// Single-character for dtype's type (ex: float is 'f' and double 'd')
char char_() const {
return detail::array_descriptor_proxy(m_ptr)->type;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth adding a comment that we're following the Python API of dtype (i.e., dtype.char), rather than NumPy's internal C API (PyArray_Descr::type), for the name?

See also https://numpy.org/devdocs/reference/c-api/types-and-structures.html#c.PyArray_Descr for the root cause of the type vs. char confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay !

}

private:
static object _dtype_from_pep3118() {
static PyObject *obj = module_::import("numpy.core._internal")
Expand Down
34 changes: 34 additions & 0 deletions tests/test_numpy_dtypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,38 @@ py::list test_dtype_ctors() {
return list;
}

py::list test_dtype_kind() {
py::list list;
for (auto& dt : {
py::dtype("bool8"), // bool
py::dtype("int16"), // short
py::dtype("int32"), // int
py::dtype("int64"), // long int
py::dtype("float32"), // float
py::dtype("float64"), // double
py::dtype("float128") // long double
}) {
list.append(dt.kind());
}
return list;
}

py::list test_dtype_type() {
py::list list;
for (auto& dt : {
py::dtype("bool8"), // bool
py::dtype("int16"), // short
py::dtype("int32"), // int
py::dtype("int64"), // long int
py::dtype("float32"), // float
py::dtype("float64"), // double
py::dtype("float128") // long double
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Winblows sizeof(long double) == sizeof(double), which might explain the error.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was about to say: MSVC doesn't really like this, @bemichel.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, those comments are not completely right: sometimes np.int32 == np.int, but sometimes np.int64 == np.int. It really depends on the platform, I think?

But then, as far as I remember (I once contributed to this part of NumPy's docstrings in a sprint at a conference), the letters are actually linked to np.bool, np.int, np.float`, etc, and not to the sized variants!

Scratch that. Seems that either they changed, or I misremember.

No, I was right. But np.int is an alias for a Python int, not for a C int, that's np.intc.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At any rate, here are the docs:
https://numpy.org/doc/stable/reference/arrays.scalars.html#built-in-scalar-types

intN or floatN are aliases, so I'd suggest using the non-alias versions.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually. It's easier if I just try fixing this. Let's see.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Let's see what this says and does.

}) {
list.append(dt.char_());
}
return list;
}

struct A {};
struct B {};

Expand Down Expand Up @@ -376,6 +408,8 @@ TEST_SUBMODULE(numpy_dtypes, m) {
return l;
});
m.def("test_dtype_ctors", &test_dtype_ctors);
m.def("test_dtype_kind", &test_dtype_kind);
m.def("test_dtype_type", &test_dtype_type);
m.def("test_dtype_methods", []() {
py::list list;
auto dt1 = py::dtype::of<int32_t>();
Expand Down
3 changes: 3 additions & 0 deletions tests/test_numpy_dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ def test_dtype(simple_dtype):
np.zeros(1, m.trailing_padding_dtype())
)

assert m.test_dtype_kind() == ["b"] + ["i"] * 3 + ["f"] * 3
assert m.test_dtype_type() == ["?", "h", "i", "l", "f", "d", "g"]


def test_recarray(simple_dtype, packed_dtype):
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
Expand Down