Skip to content

Commit 7d8f469

Browse files
committed
Operator methods include a type signature of the additional overload
Closes #2269
1 parent d54d6d8 commit 7d8f469

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
@@ -250,6 +250,7 @@ class cpp_function : public function {
250250
/* Generate a proper function signature */
251251
std::string signature;
252252
size_t type_index = 0, arg_index = 0;
253+
std::string self_type("object");
253254
for (auto *pc = text; *pc != '\0'; ++pc) {
254255
const auto c = *pc;
255256

@@ -279,9 +280,13 @@ class cpp_function : public function {
279280
pybind11_fail("Internal error while parsing type signature (1)");
280281
if (auto tinfo = detail::get_type_info(*t)) {
281282
handle th((PyObject *) tinfo->type);
282-
signature +=
283+
std::string tname =
283284
th.attr("__module__").cast<std::string>() + "." +
284285
th.attr("__qualname__").cast<std::string>(); // Python 3.3+, but we backport it to earlier versions
286+
signature += tname;
287+
if (arg_index == 0 && rec->is_method) {
288+
self_type = tname;
289+
}
285290
} else if (rec->is_new_style_constructor && arg_index == 0) {
286291
// A new-style `__init__` takes `self` as `value_and_holder`.
287292
// Rewrite it to the proper class type.
@@ -292,6 +297,9 @@ class cpp_function : public function {
292297
std::string tname(t->name());
293298
detail::clean_type_id(tname);
294299
signature += tname;
300+
if (arg_index == 0 && rec->is_method) {
301+
self_type = tname;
302+
}
295303
}
296304
} else {
297305
signature += c;
@@ -377,9 +385,10 @@ class cpp_function : public function {
377385

378386
std::string signatures;
379387
int index = 0;
388+
const bool has_overloads = (chain || rec->is_operator);
380389
/* Create a nice pydoc rec including all signatures and
381390
docstrings of the functions in the overload chain */
382-
if (chain && options::show_function_signatures()) {
391+
if (has_overloads && options::show_function_signatures()) {
383392
// First a generic signature
384393
signatures += rec->name;
385394
signatures += "(*args, **kwargs)\n";
@@ -390,7 +399,7 @@ class cpp_function : public function {
390399
for (auto it = chain_start; it != nullptr; it = it->next) {
391400
if (options::show_function_signatures()) {
392401
if (index > 0) signatures += "\n";
393-
if (chain)
402+
if (has_overloads)
394403
signatures += std::to_string(++index) + ". ";
395404
signatures += rec->name;
396405
signatures += it->signature;
@@ -408,6 +417,16 @@ class cpp_function : public function {
408417
if (options::show_function_signatures()) signatures += "\n";
409418
}
410419
}
420+
if (rec->is_operator) {
421+
signatures += "\n";
422+
signatures += std::to_string(++index) + ". ";
423+
signatures += rec->name;
424+
signatures += "(";
425+
if (rec->is_method) {
426+
signatures += "self: " + self_type + ", ";
427+
}
428+
signatures += "*args, **kwargs) -> NotImplemented\n";
429+
}
411430

412431
/* Install docstring */
413432
PyCFunctionObject *func = (PyCFunctionObject *) m_ptr;

tests/test_operator_overloading.py

+12
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,15 @@ def test_nested():
126126
assert abase.value == 42
127127
del abase, b
128128
pytest.gc_collect()
129+
130+
131+
def test_docstring_includes_type_signature(msg):
132+
"""#2269: Docstring includes a type signature of the additional overload"""
133+
assert msg(m.Vector2.__eq__.__doc__) == """
134+
__eq__(*args, **kwargs)
135+
Overloaded function.
136+
137+
1. __eq__(self: m.operators.Vector2, arg0: m.operators.Vector2) -> bool
138+
139+
2. __eq__(self: m.operators.Vector2, *args, **kwargs) -> NotImplemented
140+
"""

0 commit comments

Comments
 (0)