Skip to content

Commit 1bd6875

Browse files
committed
Operator methods include a type signature of the additional overload
Closes #2269
1 parent d46f332 commit 1bd6875

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

include/pybind11/pybind11.h

+22-3
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ class cpp_function : public function {
257257
/* Generate a proper function signature */
258258
std::string signature;
259259
size_t type_index = 0, arg_index = 0;
260+
std::string self_type("object");
260261
for (auto *pc = text; *pc != '\0'; ++pc) {
261262
const auto c = *pc;
262263

@@ -293,9 +294,13 @@ class cpp_function : public function {
293294
pybind11_fail("Internal error while parsing type signature (1)");
294295
if (auto tinfo = detail::get_type_info(*t)) {
295296
handle th((PyObject *) tinfo->type);
296-
signature +=
297+
std::string tname =
297298
th.attr("__module__").cast<std::string>() + "." +
298299
th.attr("__qualname__").cast<std::string>(); // Python 3.3+, but we backport it to earlier versions
300+
signature += tname;
301+
if (arg_index == 0 && rec->is_method) {
302+
self_type = tname;
303+
}
299304
} else if (rec->is_new_style_constructor && arg_index == 0) {
300305
// A new-style `__init__` takes `self` as `value_and_holder`.
301306
// Rewrite it to the proper class type.
@@ -306,6 +311,9 @@ class cpp_function : public function {
306311
std::string tname(t->name());
307312
detail::clean_type_id(tname);
308313
signature += tname;
314+
if (arg_index == 0 && rec->is_method) {
315+
self_type = tname;
316+
}
309317
}
310318
} else {
311319
signature += c;
@@ -404,9 +412,10 @@ class cpp_function : public function {
404412

405413
std::string signatures;
406414
int index = 0;
415+
const bool has_overloads = (chain || rec->is_operator);
407416
/* Create a nice pydoc rec including all signatures and
408417
docstrings of the functions in the overload chain */
409-
if (chain && options::show_function_signatures()) {
418+
if (has_overloads && options::show_function_signatures()) {
410419
// First a generic signature
411420
signatures += rec->name;
412421
signatures += "(*args, **kwargs)\n";
@@ -417,7 +426,7 @@ class cpp_function : public function {
417426
for (auto it = chain_start; it != nullptr; it = it->next) {
418427
if (options::show_function_signatures()) {
419428
if (index > 0) signatures += "\n";
420-
if (chain)
429+
if (has_overloads)
421430
signatures += std::to_string(++index) + ". ";
422431
signatures += rec->name;
423432
signatures += it->signature;
@@ -435,6 +444,16 @@ class cpp_function : public function {
435444
if (options::show_function_signatures()) signatures += "\n";
436445
}
437446
}
447+
if (rec->is_operator) {
448+
signatures += "\n";
449+
signatures += std::to_string(++index) + ". ";
450+
signatures += rec->name;
451+
signatures += "(";
452+
if (rec->is_method) {
453+
signatures += "self: " + self_type + ", ";
454+
}
455+
signatures += "*args, **kwargs) -> NotImplemented\n";
456+
}
438457

439458
/* Install docstring */
440459
auto *func = (PyCFunctionObject *) m_ptr;

tests/test_operator_overloading.py

+12
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,15 @@ def test_overriding_eq_reset_hash():
143143

144144
assert hash(hashable(15)) == 15
145145
assert hash(hashable(15)) == hash(hashable(15))
146+
147+
148+
def test_docstring_includes_type_signature(msg):
149+
"""#2269: Docstring includes a type signature of the additional overload"""
150+
assert msg(m.Vector2.__eq__.__doc__) == """
151+
__eq__(*args, **kwargs)
152+
Overloaded function.
153+
154+
1. __eq__(self: m.operators.Vector2, arg0: m.operators.Vector2) -> bool
155+
156+
2. __eq__(self: m.operators.Vector2, *args, **kwargs) -> NotImplemented
157+
"""

0 commit comments

Comments
 (0)