mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-21 20:55:11 +00:00
Add additional info to TypeError when C++->Python casting fails (#3605)
* Add additional info to TypeInfo when C++->Python casting fails * Fix typo * Address reviewer comments
This commit is contained in:
parent
b66328b043
commit
ef070f7750
@ -996,6 +996,13 @@ protected:
|
||||
"Python type! The signature was\n\t";
|
||||
msg += it->signature;
|
||||
append_note_if_missing_header_is_suspected(msg);
|
||||
#if PY_VERSION_HEX >= 0x03030000
|
||||
// Attach additional error info to the exception if supported
|
||||
if (PyErr_Occurred()) {
|
||||
raise_from(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7,10 +7,11 @@
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
#include "constructor_stats.h"
|
||||
#include <pybind11/operators.h>
|
||||
#include "pybind11_tests.h"
|
||||
#include <functional>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
class Vector2 {
|
||||
public:
|
||||
@ -71,6 +72,12 @@ int operator+(const C2 &, const C2 &) { return 22; }
|
||||
int operator+(const C2 &, const C1 &) { return 21; }
|
||||
int operator+(const C1 &, const C2 &) { return 12; }
|
||||
|
||||
struct HashMe {
|
||||
std::string member;
|
||||
};
|
||||
|
||||
bool operator==(const HashMe &lhs, const HashMe &rhs) { return lhs.member == rhs.member; }
|
||||
|
||||
// Note: Specializing explicit within `namespace std { ... }` is done due to a
|
||||
// bug in GCC<7. If you are supporting compilers later than this, consider
|
||||
// specializing `using template<> struct std::hash<...>` in the global
|
||||
@ -82,6 +89,14 @@ namespace std {
|
||||
// Not a good hash function, but easy to test
|
||||
size_t operator()(const Vector2 &) { return 4; }
|
||||
};
|
||||
|
||||
// HashMe has a hash function in C++ but no `__hash__` for Python.
|
||||
template <>
|
||||
struct hash<HashMe> {
|
||||
std::size_t operator()(const HashMe &selector) const {
|
||||
return std::hash<std::string>()(selector.member);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
// Not a good abs function, but easy to test.
|
||||
@ -228,8 +243,12 @@ TEST_SUBMODULE(operators, m) {
|
||||
.def("__hash__", &Hashable::hash)
|
||||
.def(py::init<int>())
|
||||
.def(py::self == py::self);
|
||||
}
|
||||
|
||||
// define __eq__ but not __hash__
|
||||
py::class_<HashMe>(m, "HashMe").def(py::self == py::self);
|
||||
|
||||
m.def("get_unhashable_HashMe_set", []() { return std::unordered_set<HashMe>{{"one"}}; });
|
||||
}
|
||||
#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env
|
||||
from pybind11_tests import ConstructorStats
|
||||
from pybind11_tests import operators as m
|
||||
|
||||
@ -135,8 +136,9 @@ def test_overriding_eq_reset_hash():
|
||||
assert m.Comparable(15) is not m.Comparable(15)
|
||||
assert m.Comparable(15) == m.Comparable(15)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
hash(m.Comparable(15)) # TypeError: unhashable type: 'm.Comparable'
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
hash(m.Comparable(15))
|
||||
assert str(excinfo.value).startswith("unhashable type:")
|
||||
|
||||
for hashable in (m.Hashable, m.Hashable2):
|
||||
assert hashable(15) is not hashable(15)
|
||||
@ -144,3 +146,10 @@ def test_overriding_eq_reset_hash():
|
||||
|
||||
assert hash(hashable(15)) == 15
|
||||
assert hash(hashable(15)) == hash(hashable(15))
|
||||
|
||||
|
||||
def test_return_set_of_unhashable():
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.get_unhashable_HashMe_set()
|
||||
if not env.PY2:
|
||||
assert str(excinfo.value.__cause__).startswith("unhashable type:")
|
||||
|
Loading…
Reference in New Issue
Block a user