Skip to content

Commit 70ace77

Browse files
committed
Add support for showing all overload signatures for a function.
1 parent 8916055 commit 70ace77

File tree

4 files changed

+114
-12
lines changed

4 files changed

+114
-12
lines changed

pdoc/doc.py

+75-10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@
3939
from typing import TypeVar
4040
from typing import Union
4141
from typing import get_origin
42+
43+
try:
44+
# This only exists on Python 3.11 and later. On older versions,
45+
# we just replace it with a function that does nothing.
46+
from typing import get_overloads
47+
except ImportError:
48+
from typing import Sequence
49+
50+
def get_overloads(func: Callable[..., object]) -> Sequence[Callable[..., object]]:
51+
return []
52+
53+
4254
import warnings
4355

4456
from pdoc import doc_ast
@@ -989,6 +1001,69 @@ def signature(self) -> inspect.Signature:
9891001
return inspect.Signature(
9901002
[inspect.Parameter("unknown", inspect.Parameter.POSITIONAL_OR_KEYWORD)]
9911003
)
1004+
1005+
return self._process_signature(sig)
1006+
1007+
@cached_property
1008+
def signature_without_self(self) -> inspect.Signature:
1009+
"""Like `signature`, but without the first argument.
1010+
1011+
This is useful to display constructors.
1012+
"""
1013+
return self.signature.replace(
1014+
parameters=list(self.signature.parameters.values())[1:]
1015+
)
1016+
1017+
@cached_property
1018+
def overloads(self) -> list[inspect.Signature]:
1019+
"""
1020+
The function's overloaded signatures, if any.
1021+
1022+
This should do the same processing as `signature`, but can return a list
1023+
of additional signatures when available.
1024+
"""
1025+
1026+
if self.obj is object.__init__:
1027+
# See `signature`.
1028+
return [inspect.Signature()]
1029+
1030+
try:
1031+
values = get_overloads(self.obj)
1032+
except Exception:
1033+
return []
1034+
1035+
results = []
1036+
for value in values:
1037+
try:
1038+
sig = _PrettySignature.from_callable(value)
1039+
results.append(self._process_signature(sig))
1040+
except Exception:
1041+
sig_err = inspect.Signature(
1042+
[
1043+
inspect.Parameter(
1044+
"unknown", inspect.Parameter.POSITIONAL_OR_KEYWORD
1045+
)
1046+
]
1047+
)
1048+
results.append(sig_err)
1049+
return results
1050+
1051+
@cached_property
1052+
def overloads_without_self(self) -> list[inspect.Signature]:
1053+
"""Like `overloads`, but without the first argument.
1054+
1055+
This is useful to display constructors.
1056+
"""
1057+
return [
1058+
sig.replace(parameters=list(self.signature.parameters.values())[1:])
1059+
for sig in self.overloads
1060+
]
1061+
1062+
def _process_signature(self, sig: inspect.Signature) -> inspect.Signature:
1063+
"""
1064+
A helper method for `signature` and `overloads` which performs
1065+
necessary post-processing on a signature object.
1066+
"""
9921067
mod = inspect.getmodule(self.obj)
9931068
globalns = _safe_getattr(mod, "__dict__", {})
9941069
localns = globalns
@@ -1012,16 +1087,6 @@ def signature(self) -> inspect.Signature:
10121087
)
10131088
return sig
10141089

1015-
@cached_property
1016-
def signature_without_self(self) -> inspect.Signature:
1017-
"""Like `signature`, but without the first argument.
1018-
1019-
This is useful to display constructors.
1020-
"""
1021-
return self.signature.replace(
1022-
parameters=list(self.signature.parameters.values())[1:]
1023-
)
1024-
10251090

10261091
class Variable(Doc[None]):
10271092
"""

pdoc/doc_pyi.py

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def _patch_doc(target_doc: doc.Doc, stub_mod: doc.Module) -> None:
7777
stub_doc.docstring = ""
7878

7979
target_doc.signature = stub_doc.signature
80+
target_doc.overloads = stub_doc.overloads
8081
target_doc.funcdef = stub_doc.funcdef
8182
target_doc.docstring = stub_doc.docstring or target_doc.docstring
8283
elif isinstance(target_doc, doc.Variable) and isinstance(stub_doc, doc.Variable):

pdoc/templates/content.css

+13
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,19 @@ This makes sure that the pdoc styling doesn't leak to the rest of the page when
300300
overflow-x: auto;
301301
}
302302

303+
.pdoc .overloads {
304+
margin-left: 2rem;
305+
}
306+
307+
/* The same as .pdoc .attr, but without the focused/target/hover rules. */
308+
.pdoc .extra-attr {
309+
display: block;
310+
margin: .5rem 0 .5rem;
311+
padding: .4rem .4rem .4rem 1rem;
312+
background-color: var(--accent);
313+
overflow-x: auto;
314+
}
315+
303316
.pdoc .classattr {
304317
margin-left: 2rem;
305318
}

pdoc/templates/default/module.html.jinja2

+25-2
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,30 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
172172
{{- fn.signature_without_self | format_signature(colon=False) | linkify }}
173173
{% else %}
174174
<span class="def">{{ fn.funcdef }}</span>
175-
<span class="name">{{ fn.name }}</span>
176-
{{- fn.signature | format_signature(colon=True) | linkify }}
175+
<span class="name">{{ fn.name }}</span>
176+
{{- fn.signature | format_signature(colon=True) | linkify }}
177177
{% endif %}
178178
{% enddefaultmacro %}
179+
{% defaultmacro overloads(fn) -%}
180+
<div class="overloads">
181+
{% if fn.name == "__init__" %}
182+
{% for sig in fn.overloads_without_self %}
183+
<div class="extra-attr {{ fn.kind }}">
184+
<span class="name">{{ ".".join(fn.qualname.split(".")[:-1]) }}</span>
185+
{{- sig | format_signature(colon=False) | linkify }}
186+
</div>
187+
{% endfor %}
188+
{% else %}
189+
{% for sig in fn.overloads %}
190+
<div class="extra-attr {{ fn.kind }}">
191+
<span class="def">{{ fn.funcdef }}</span>
192+
<span class="name">{{ fn.name }}</span>
193+
{{- sig | format_signature(colon=True) | linkify }}
194+
</div>
195+
{% endfor %}
196+
{% endif %}
197+
</div>
198+
{% enddefaultmacro %}
179199
{% defaultmacro variable(var) -%}
180200
{%- if var.is_type_alias_type %}<span class="def">type</span> {% endif -%}
181201
<span class="name">{{ var.name }}</span>{{ annotation(var) }}{{ default_value(var) }}
@@ -203,6 +223,9 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
203223
{% endif %}
204224
{{ view_source_button(doc) }}
205225
</div>
226+
{% if doc.kind == "function" and doc.overloads|length > 0 %}
227+
{{ overloads(doc) }}
228+
{% endif %}
206229
<a class="headerlink" href="#{{ doc.qualname or doc.name }}"></a>
207230
{{ view_source_code(doc) }}
208231
{{ docstring(doc) }}

0 commit comments

Comments
 (0)