Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sphinx multimethod customization (#1120 #1121 #1122) #1123

Merged
merged 1 commit into from
Aug 6, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 16 additions & 10 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os
import sys, os, re
import os.path

# print "working path is %s" % os.getcwd()
Expand Down Expand Up @@ -59,8 +59,8 @@
master_doc = "index"

# General information about the project.
project = u"CadQuery"
copyright = u"Parametric Products Intellectual Holdings LLC, All Rights Reserved"
project = "CadQuery"
copyright = "Parametric Products Intellectual Holdings LLC, All Rights Reserved"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
Expand Down Expand Up @@ -227,7 +227,7 @@
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
("index", "CadQuery.tex", u"CadQuery Documentation", u"David Cowden", "manual"),
("index", "CadQuery.tex", "CadQuery Documentation", "David Cowden", "manual"),
]

# The name of an image file (relative to this directory) to place at the top of
Expand Down Expand Up @@ -255,7 +255,7 @@

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [("index", "cadquery", u"CadQuery Documentation", [u"David Cowden"], 1)]
man_pages = [("index", "cadquery", "CadQuery Documentation", ["David Cowden"], 1)]

# If true, show URL addresses after external links.
# man_show_urls = False
Expand All @@ -270,8 +270,8 @@
(
"index",
"CadQuery",
u"CadQuery Documentation",
u"David Cowden",
"CadQuery Documentation",
"David Cowden",
"CadQuery",
"A Fluent CAD api",
"Miscellaneous",
Expand All @@ -288,19 +288,25 @@
# texinfo_show_urls = 'footnote'


patparam = re.compile(r"(\W*):\W*param.*")


def process_docstring_insert_self(app, what, name, obj, options, lines):
"""
Insert self in front of documented params for instance methods
"""

if (
what == "method"
and app.config.autodoc_typehints in ("both", "description")
and app.config.autodoc_typehints_description_target in ("all")
and getattr(obj, "__self__", None) is None
and "self" in obj.__annotations__
):
for i, dstr in enumerate(lines):
if dstr.startswith(":param"):
lines.insert(i, ":param self:")
for i, line in enumerate(lines):
if m := patparam.match(line):
indent = m.group(1)
lines.insert(i, f"{indent}:param self:")
break


Expand Down
62 changes: 25 additions & 37 deletions doc/ext/sphinx_autodoc_multimethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,51 +27,26 @@ def get_first(obj):
return next(iter(obj))


patself = re.compile(r"\W*:\W*param\W+self.*")
patparam = re.compile(r"\W*:\W*param.*")
patindent = re.compile(r"(\W*)")


def process_docstring_multimethod(app, what, name, obj, options, lines):
"""multimethod docstring customization

* formatting and remove extraneous signatures
* insert self in front of param field list for instance methods if type hinted
Remove extraneous signatures and combine docstrings if docstring also defined
in registered methods. Requires sphinx-build -E if rebuilding docs.
"""

methods = []

if what == "method" and isinstance(obj, multimethod):
# instance or static method

insert_first_param = False
if (
app.config.autodoc_typehints in ("both", "description")
and app.config.autodoc_typehints_description_target in ("all")
and get_first(get_type_hints(get_first(obj.values()))) == "self"
):
insert_first_param = True

lines_replace = []

# handle functools.singledispatch style register (multiple names)
methods = set(m.__name__ for m in obj.values())
patsig = re.compile(rf"\W*[{'|'.join(methods)}]+\(.*\).*")

iparam = None
for i, line in enumerate(lines):
if patsig.match(line):
lines_replace.append("")
continue
if insert_first_param and patself.match(line):
# exists explicitly in field list
insert_first_param = False
elif insert_first_param and not iparam and patparam.match(line):
iparam = i
lines_replace.append(line.lstrip())

if insert_first_param and iparam:
lines_replace.insert(iparam, ":param self:")

del lines[:]
lines.extend(lines_replace)
if obj.pending:
methods = set(m.__name__ for m in obj.pending)
else:
methods = set(m.__name__ for m in obj.values())

elif what == "method" and inspect.isclassmethod(obj) and hasattr(obj, "pending"):

Expand All @@ -80,14 +55,23 @@ def process_docstring_multimethod(app, what, name, obj, options, lines):
else:
methods = set(m.__name__ for m in obj.__func__.values())

if methods:
lines_replace = []
patsig = re.compile(rf"\W*[{'|'.join(methods)}]+\(.*\).*")

indent = -1
for line in lines:
if indent < 0:
# fix indent when multiple docstrings defined
if m := patindent.match(line):
indent = len(m.group(1))
else:
indent = 0

if patsig.match(line):
lines_replace.append("")
else:
lines_replace.append(line.lstrip())
lines_replace.append(line[indent:])

del lines[:]
lines.extend(lines_replace)
Expand Down Expand Up @@ -243,12 +227,16 @@ def format_signature(self, **kwargs: Any) -> str:
sigs.append(documenter.format_signature())
# -- multimethod customization
elif isinstance(meth, multimethod):
sigs = self.append_signature_multiple_dispatch(meth.values())
if meth.pending:
methods = meth.pending
else:
methods = set(meth.values())
sigs = self.append_signature_multiple_dispatch(methods)
elif inspect.isclassmethod(self.object) and hasattr(self.object, "pending"):
if self.object.pending:
methods = self.object.pending
else:
methods = self.object.__func__.values()
methods = set(self.object.__func__.values())
sigs = self.append_signature_multiple_dispatch(methods)
elif inspect.isstaticmethod(meth) and isinstance(self.object, multimethod):
sigs = []
Expand Down