Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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: 7 additions & 0 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,13 @@ class cpp_function : public function {
"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;
}
Expand Down
24 changes: 21 additions & 3 deletions tests/test_operator_overloading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -82,6 +89,13 @@ namespace std {
// Not a good hash function, but easy to test
size_t operator()(const Vector2 &) { return 4; }
};

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.
Expand Down Expand Up @@ -228,8 +242,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
8 changes: 8 additions & 0 deletions tests/test_operator_overloading.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import pytest

import env
from pybind11_tests import ConstructorStats
from pybind11_tests import operators as m

Expand Down Expand Up @@ -144,3 +145,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:")