mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
pytypes: Add Gotchas section about default-constructed wrapper types and py::none() (#2362)
This commit is contained in:
parent
72b06b86b3
commit
44fa79ca80
@ -15,6 +15,11 @@ Available types include :class:`handle`, :class:`object`, :class:`bool_`,
|
||||
:class:`iterable`, :class:`iterator`, :class:`function`, :class:`buffer`,
|
||||
:class:`array`, and :class:`array_t`.
|
||||
|
||||
.. warning::
|
||||
|
||||
Be sure to review the :ref:`pytypes_gotchas` before using this heavily in
|
||||
your C++ API.
|
||||
|
||||
Casting back and forth
|
||||
======================
|
||||
|
||||
@ -178,3 +183,25 @@ Python exceptions from wrapper classes will be thrown as a ``py::error_already_s
|
||||
See :ref:`Handling exceptions from Python in C++
|
||||
<handling_python_exceptions_cpp>` for more information on handling exceptions
|
||||
raised when calling C++ wrapper classes.
|
||||
|
||||
.. _pytypes_gotchas:
|
||||
|
||||
Gotchas
|
||||
=======
|
||||
|
||||
Default-Constructed Wrappers
|
||||
----------------------------
|
||||
|
||||
When a wrapper type is default-constructed, it is **not** a valid Python object (i.e. it is not ``py::none()``). It is simply the same as
|
||||
``PyObject*`` null pointer. To check for this, use
|
||||
``static_cast<bool>(my_wrapper)``.
|
||||
|
||||
Assigning py::none() to wrappers
|
||||
--------------------------------
|
||||
|
||||
You may be tempted to use types like ``py::str`` and ``py::dict`` in C++
|
||||
signatures (either pure C++, or in bound signatures), and assign them default
|
||||
values of ``py::none()``. However, in a best case scenario, it will fail fast
|
||||
because ``None`` is not convertible to that type (e.g. ``py::dict``), or in a
|
||||
worse case scenario, it will silently work but corrupt the types you want to
|
||||
work with (e.g. ``py::str(py::none())`` will yield ``"None"`` in Python).
|
||||
|
@ -324,6 +324,16 @@ TEST_SUBMODULE(pytypes, m) {
|
||||
return a[py::slice(0, -1, 2)];
|
||||
});
|
||||
|
||||
// See #2361
|
||||
m.def("issue2361_str_implicit_copy_none", []() {
|
||||
py::str is_this_none = py::none();
|
||||
return is_this_none;
|
||||
});
|
||||
m.def("issue2361_dict_implicit_copy_none", []() {
|
||||
py::dict is_this_none = py::none();
|
||||
return is_this_none;
|
||||
});
|
||||
|
||||
m.def("test_memoryview_object", [](py::buffer b) {
|
||||
return py::memoryview(b);
|
||||
});
|
||||
|
@ -326,6 +326,14 @@ def test_list_slicing():
|
||||
assert li[::2] == m.test_list_slicing(li)
|
||||
|
||||
|
||||
def test_issue2361():
|
||||
# See issue #2361
|
||||
assert m.issue2361_str_implicit_copy_none() == "None"
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
assert m.issue2361_dict_implicit_copy_none()
|
||||
assert "'NoneType' object is not iterable" in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('method, args, fmt, expected_view', [
|
||||
(m.test_memoryview_object, (b'red',), 'B', b'red'),
|
||||
(m.test_memoryview_buffer_info, (b'green',), 'B', b'green'),
|
||||
|
Loading…
Reference in New Issue
Block a user