Skip to content

Commit

Permalink
Add support for showing all overload signatures for a function.
Browse files Browse the repository at this point in the history
  • Loading branch information
daemontus committed Jan 23, 2024
1 parent 8916055 commit 70ace77
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 12 deletions.
85 changes: 75 additions & 10 deletions pdoc/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@
from typing import TypeVar
from typing import Union
from typing import get_origin

try:
# This only exists on Python 3.11 and later. On older versions,
# we just replace it with a function that does nothing.
from typing import get_overloads
except ImportError:
from typing import Sequence

def get_overloads(func: Callable[..., object]) -> Sequence[Callable[..., object]]:
return []


import warnings

from pdoc import doc_ast
Expand Down Expand Up @@ -989,6 +1001,69 @@ def signature(self) -> inspect.Signature:
return inspect.Signature(
[inspect.Parameter("unknown", inspect.Parameter.POSITIONAL_OR_KEYWORD)]
)

return self._process_signature(sig)

@cached_property
def signature_without_self(self) -> inspect.Signature:
"""Like `signature`, but without the first argument.
This is useful to display constructors.
"""
return self.signature.replace(
parameters=list(self.signature.parameters.values())[1:]
)

@cached_property
def overloads(self) -> list[inspect.Signature]:
"""
The function's overloaded signatures, if any.
This should do the same processing as `signature`, but can return a list
of additional signatures when available.
"""

if self.obj is object.__init__:
# See `signature`.
return [inspect.Signature()]

try:
values = get_overloads(self.obj)
except Exception:
return []

results = []
for value in values:
try:
sig = _PrettySignature.from_callable(value)
results.append(self._process_signature(sig))
except Exception:
sig_err = inspect.Signature(
[
inspect.Parameter(
"unknown", inspect.Parameter.POSITIONAL_OR_KEYWORD
)
]
)
results.append(sig_err)
return results

@cached_property
def overloads_without_self(self) -> list[inspect.Signature]:
"""Like `overloads`, but without the first argument.
This is useful to display constructors.
"""
return [
sig.replace(parameters=list(self.signature.parameters.values())[1:])
for sig in self.overloads
]

def _process_signature(self, sig: inspect.Signature) -> inspect.Signature:
"""
A helper method for `signature` and `overloads` which performs
necessary post-processing on a signature object.
"""
mod = inspect.getmodule(self.obj)
globalns = _safe_getattr(mod, "__dict__", {})
localns = globalns
Expand All @@ -1012,16 +1087,6 @@ def signature(self) -> inspect.Signature:
)
return sig

@cached_property
def signature_without_self(self) -> inspect.Signature:
"""Like `signature`, but without the first argument.
This is useful to display constructors.
"""
return self.signature.replace(
parameters=list(self.signature.parameters.values())[1:]
)


class Variable(Doc[None]):
"""
Expand Down
1 change: 1 addition & 0 deletions pdoc/doc_pyi.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def _patch_doc(target_doc: doc.Doc, stub_mod: doc.Module) -> None:
stub_doc.docstring = ""

target_doc.signature = stub_doc.signature
target_doc.overloads = stub_doc.overloads
target_doc.funcdef = stub_doc.funcdef
target_doc.docstring = stub_doc.docstring or target_doc.docstring
elif isinstance(target_doc, doc.Variable) and isinstance(stub_doc, doc.Variable):
Expand Down
13 changes: 13 additions & 0 deletions pdoc/templates/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,19 @@ This makes sure that the pdoc styling doesn't leak to the rest of the page when
overflow-x: auto;
}

.pdoc .overloads {
margin-left: 2rem;
}

/* The same as .pdoc .attr, but without the focused/target/hover rules. */
.pdoc .extra-attr {
display: block;
margin: .5rem 0 .5rem;
padding: .4rem .4rem .4rem 1rem;
background-color: var(--accent);
overflow-x: auto;
}

.pdoc .classattr {
margin-left: 2rem;
}
Expand Down
27 changes: 25 additions & 2 deletions pdoc/templates/default/module.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,30 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
{{- fn.signature_without_self | format_signature(colon=False) | linkify }}
{% else %}
<span class="def">{{ fn.funcdef }}</span>
<span class="name">{{ fn.name }}</span>
{{- fn.signature | format_signature(colon=True) | linkify }}
<span class="name">{{ fn.name }}</span>
{{- fn.signature | format_signature(colon=True) | linkify }}
{% endif %}
{% enddefaultmacro %}
{% defaultmacro overloads(fn) -%}
<div class="overloads">
{% if fn.name == "__init__" %}
{% for sig in fn.overloads_without_self %}
<div class="extra-attr {{ fn.kind }}">
<span class="name">{{ ".".join(fn.qualname.split(".")[:-1]) }}</span>
{{- sig | format_signature(colon=False) | linkify }}
</div>
{% endfor %}
{% else %}
{% for sig in fn.overloads %}
<div class="extra-attr {{ fn.kind }}">
<span class="def">{{ fn.funcdef }}</span>
<span class="name">{{ fn.name }}</span>
{{- sig | format_signature(colon=True) | linkify }}
</div>
{% endfor %}
{% endif %}
</div>
{% enddefaultmacro %}
{% defaultmacro variable(var) -%}
{%- if var.is_type_alias_type %}<span class="def">type</span> {% endif -%}
<span class="name">{{ var.name }}</span>{{ annotation(var) }}{{ default_value(var) }}
Expand Down Expand Up @@ -203,6 +223,9 @@ See https://pdoc.dev/docs/pdoc/render_helpers.html#DefaultMacroExtension for an
{% endif %}
{{ view_source_button(doc) }}
</div>
{% if doc.kind == "function" and doc.overloads|length > 0 %}
{{ overloads(doc) }}
{% endif %}
<a class="headerlink" href="#{{ doc.qualname or doc.name }}"></a>
{{ view_source_code(doc) }}
{{ docstring(doc) }}
Expand Down

0 comments on commit 70ace77

Please sign in to comment.