summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarrod Millman <jarrod.millman@gmail.com>2022-05-07 19:39:02 -0700
committerJarrod Millman <jarrod.millman@gmail.com>2022-05-07 19:43:09 -0700
commit4b38c01e680cf2032acb09819bc0985e5dfc5ca8 (patch)
tree7406d44c4f64d6299526bb3348ad02307ccf572a
parent90c785975a65f064eb3bef40f9a50b8edd5af102 (diff)
downloadnumpydoc-4b38c01e680cf2032acb09819bc0985e5dfc5ca8.tar.gz
Run black formatter
-rw-r--r--doc/conf.py62
-rw-r--r--doc/example.py2
-rw-r--r--numpydoc/__init__.py2
-rw-r--r--numpydoc/__main__.py28
-rw-r--r--numpydoc/_version.py2
-rw-r--r--numpydoc/docscrape.py365
-rw-r--r--numpydoc/docscrape_sphinx.py270
-rw-r--r--numpydoc/numpydoc.py198
-rw-r--r--numpydoc/tests/test_docscrape.py603
-rw-r--r--numpydoc/tests/test_full.py65
-rw-r--r--numpydoc/tests/test_main.py48
-rw-r--r--numpydoc/tests/test_numpydoc.py128
-rw-r--r--numpydoc/tests/test_validate.py32
-rw-r--r--numpydoc/tests/test_xref.py12
-rw-r--r--numpydoc/tests/tinybuild/conf.py22
-rw-r--r--numpydoc/tests/tinybuild/numpydoc_test_module.py2
-rw-r--r--numpydoc/validate.py51
-rw-r--r--numpydoc/xref.py106
-rw-r--r--setup.py56
19 files changed, 1113 insertions, 941 deletions
diff --git a/doc/conf.py b/doc/conf.py
index 28708d8..16e1ac3 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -21,11 +21,11 @@ import os
# documentation root, use os.path.abspath to make it absolute, like shown here.
# for example.py
-sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath("."))
# project root
-sys.path.insert(0, os.path.abspath('..'))
+sys.path.insert(0, os.path.abspath(".."))
-os.environ['MPLBACKEND'] = 'Agg' # avoid tkinter import errors on rtfd.io
+os.environ["MPLBACKEND"] = "Agg" # avoid tkinter import errors on rtfd.io
# -- General configuration ---------------------------------------------------
@@ -36,32 +36,32 @@ os.environ['MPLBACKEND'] = 'Agg' # avoid tkinter import errors on rtfd.io
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
- 'sphinx.ext.autodoc',
- 'sphinx.ext.autosummary',
- 'sphinx.ext.doctest',
- 'sphinx.ext.intersphinx',
- 'sphinx.ext.todo',
- 'numpydoc',
- 'sphinx.ext.ifconfig',
- 'sphinx.ext.viewcode',
- 'sphinx.ext.imgmath',
+ "sphinx.ext.autodoc",
+ "sphinx.ext.autosummary",
+ "sphinx.ext.doctest",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.todo",
+ "numpydoc",
+ "sphinx.ext.ifconfig",
+ "sphinx.ext.viewcode",
+ "sphinx.ext.imgmath",
]
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
# The suffix of source filenames.
-source_suffix = '.rst'
+source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The root toctree document
-master_doc = 'index' # NOTE: will be changed to `root_doc` in sphinx 4
+master_doc = "index" # NOTE: will be changed to `root_doc` in sphinx 4
# General information about the project.
-project = 'numpydoc'
-copyright = f'2019-{date.today().year}, numpydoc maintainers'
+project = "numpydoc"
+copyright = f"2019-{date.today().year}, numpydoc maintainers"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -70,12 +70,13 @@ copyright = f'2019-{date.today().year}, numpydoc maintainers'
# The short X.Y version.
import numpydoc
+
# version = .__version__
# The full version, including alpha/beta/rc tags.
release = numpydoc.__version__
version = numpydoc.__version__
numpydoc_xref_param_type = True
-numpydoc_xref_ignore = {'optional', 'type_without_description', 'BadException'}
+numpydoc_xref_ignore = {"optional", "type_without_description", "BadException"}
# Run docstring validation as part of build process
numpydoc_validation_checks = {"all", "GL01", "SA04", "RT03"}
@@ -91,7 +92,7 @@ numpydoc_validation_checks = {"all", "GL01", "SA04", "RT03"}
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
+exclude_patterns = ["_build"]
# The reST default role (used for this markup: `text`) to use for all
# documents.
@@ -109,7 +110,7 @@ exclude_patterns = ['_build']
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
@@ -134,7 +135,7 @@ html_sidebars = {
}
html_title = f"{project} v{version} Manual"
-html_last_updated_fmt = '%b %d, %Y'
+html_last_updated_fmt = "%b %d, %Y"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -188,7 +189,7 @@ html_static_path = [] # ['_static']
# html_file_suffix = None
# Output file base name for HTML help builder.
-htmlhelp_basename = 'project-templatedoc'
+htmlhelp_basename = "project-templatedoc"
# -- Options for LaTeX output ---------------------------------------------
@@ -196,10 +197,8 @@ htmlhelp_basename = 'project-templatedoc'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper',
-
# The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt',
-
# Additional stuff for the LaTeX preamble.
# 'preamble': '',
}
@@ -208,8 +207,13 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
- ('index', 'numpydoc.tex', 'numpydoc Documentation',
- 'Numpydoc maintainers', 'manual'),
+ (
+ "index",
+ "numpydoc.tex",
+ "numpydoc Documentation",
+ "Numpydoc maintainers",
+ "manual",
+ ),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -247,7 +251,7 @@ latex_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
- 'python': ('https://docs.python.org/3/', None),
- 'numpy': ('https://numpy.org/devdocs/', None),
- 'sklearn': ('https://scikit-learn.org/stable/', None),
+ "python": ("https://docs.python.org/3/", None),
+ "numpy": ("https://numpy.org/devdocs/", None),
+ "sklearn": ("https://scikit-learn.org/stable/", None),
}
diff --git a/doc/example.py b/doc/example.py
index 3e93a82..9d3ecca 100644
--- a/doc/example.py
+++ b/doc/example.py
@@ -34,7 +34,7 @@ import matplotlib.pyplot as plt
# numpy module itself, unabbreviated.
-def foo(var1, var2, *args, long_var_name='hi', only_seldom_used_keyword=0, **kwargs):
+def foo(var1, var2, *args, long_var_name="hi", only_seldom_used_keyword=0, **kwargs):
r"""Summarize the function in one line.
Several sentences providing an extended description. Refer to
diff --git a/numpydoc/__init__.py b/numpydoc/__init__.py
index 42836ff..31cc424 100644
--- a/numpydoc/__init__.py
+++ b/numpydoc/__init__.py
@@ -20,6 +20,7 @@ def _verify_sphinx_jinja():
if version.parse(sphinx.__version__) <= version.parse("4.0.2"):
if version.parse(jinja2.__version__) >= version.parse("3.1"):
from sphinx.errors import VersionRequirementError
+
raise VersionRequirementError(
"\n\nSphinx<4.0.2 is incompatible with Jinja2>=3.1.\n"
"If you wish to continue using sphinx<4.0.2 you need to pin "
@@ -32,4 +33,5 @@ _verify_sphinx_jinja()
def setup(app, *args, **kwargs):
from .numpydoc import setup
+
return setup(app, *args, **kwargs)
diff --git a/numpydoc/__main__.py b/numpydoc/__main__.py
index f342cc3..4a50da9 100644
--- a/numpydoc/__main__.py
+++ b/numpydoc/__main__.py
@@ -12,8 +12,7 @@ from .validate import validate, Validator
def render_object(import_path, config=None):
"""Test numpydoc docstring generation for a given object"""
# TODO: Move Validator._load_obj to a better place than validate
- print(get_doc_object(Validator._load_obj(import_path),
- config=dict(config or [])))
+ print(get_doc_object(Validator._load_obj(import_path), config=dict(config or [])))
return 0
@@ -22,25 +21,30 @@ def validate_object(import_path):
results = validate(import_path)
for err_code, err_desc in results["errors"]:
exit_status += 1
- print(':'.join([import_path, err_code, err_desc]))
+ print(":".join([import_path, err_code, err_desc]))
return exit_status
-if __name__ == '__main__':
+if __name__ == "__main__":
ap = argparse.ArgumentParser(description=__doc__)
- ap.add_argument('import_path', help='e.g. numpy.ndarray')
+ ap.add_argument("import_path", help="e.g. numpy.ndarray")
def _parse_config(s):
- key, _, value = s.partition('=')
+ key, _, value = s.partition("=")
value = ast.literal_eval(value)
return key, value
- ap.add_argument('-c', '--config', type=_parse_config,
- action='append',
- help='key=val where val will be parsed by literal_eval, '
- 'e.g. -c use_plots=True. Multiple -c can be used.')
- ap.add_argument('--validate', action='store_true',
- help='validate the object and report errors')
+ ap.add_argument(
+ "-c",
+ "--config",
+ type=_parse_config,
+ action="append",
+ help="key=val where val will be parsed by literal_eval, "
+ "e.g. -c use_plots=True. Multiple -c can be used.",
+ )
+ ap.add_argument(
+ "--validate", action="store_true", help="validate the object and report errors"
+ )
args = ap.parse_args()
if args.validate:
diff --git a/numpydoc/_version.py b/numpydoc/_version.py
index e7a1397..0196c1d 100644
--- a/numpydoc/_version.py
+++ b/numpydoc/_version.py
@@ -1 +1 @@
-__version__ = '1.3.2.dev0'
+__version__ = "1.3.2.dev0"
diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py
index 1587797..6bdaa84 100644
--- a/numpydoc/docscrape.py
+++ b/numpydoc/docscrape.py
@@ -22,9 +22,8 @@ def strip_blank_lines(l):
class Reader:
- """A line-based string reader.
+ """A line-based string reader."""
- """
def __init__(self, data):
"""
Parameters
@@ -36,7 +35,7 @@ class Reader:
if isinstance(data, list):
self._str = data
else:
- self._str = data.split('\n') # store string as list of lines
+ self._str = data.split("\n") # store string as list of lines
self.reset()
@@ -52,10 +51,10 @@ class Reader:
self._l += 1
return out
else:
- return ''
+ return ""
def seek_next_non_empty_line(self):
- for l in self[self._l:]:
+ for l in self[self._l :]:
if l.strip():
break
else:
@@ -68,10 +67,10 @@ class Reader:
start = self._l
for line in self[start:]:
if condition_func(line):
- return self[start:self._l]
+ return self[start : self._l]
self._l += 1
if self.eof():
- return self[start:self._l+1]
+ return self[start : self._l + 1]
return []
def read_to_next_empty_line(self):
@@ -84,28 +83,29 @@ class Reader:
def read_to_next_unindented_line(self):
def is_unindented(line):
- return (line.strip() and (len(line.lstrip()) == len(line)))
+ return line.strip() and (len(line.lstrip()) == len(line))
+
return self.read_to_condition(is_unindented)
def peek(self, n=0):
if self._l + n < len(self._str):
return self[self._l + n]
else:
- return ''
+ return ""
def is_empty(self):
- return not ''.join(self._str).strip()
+ return not "".join(self._str).strip()
class ParseError(Exception):
def __str__(self):
message = self.args[0]
- if hasattr(self, 'docstring'):
+ if hasattr(self, "docstring"):
message = f"{message} in {self.docstring!r}"
return message
-Parameter = namedtuple('Parameter', ['name', 'type', 'desc'])
+Parameter = namedtuple("Parameter", ["name", "type", "desc"])
class NumpyDocString(Mapping):
@@ -116,29 +116,29 @@ class NumpyDocString(Mapping):
"""
sections = {
- 'Signature': '',
- 'Summary': [''],
- 'Extended Summary': [],
- 'Parameters': [],
- 'Returns': [],
- 'Yields': [],
- 'Receives': [],
- 'Raises': [],
- 'Warns': [],
- 'Other Parameters': [],
- 'Attributes': [],
- 'Methods': [],
- 'See Also': [],
- 'Notes': [],
- 'Warnings': [],
- 'References': '',
- 'Examples': '',
- 'index': {}
+ "Signature": "",
+ "Summary": [""],
+ "Extended Summary": [],
+ "Parameters": [],
+ "Returns": [],
+ "Yields": [],
+ "Receives": [],
+ "Raises": [],
+ "Warns": [],
+ "Other Parameters": [],
+ "Attributes": [],
+ "Methods": [],
+ "See Also": [],
+ "Notes": [],
+ "Warnings": [],
+ "References": "",
+ "Examples": "",
+ "index": {},
}
def __init__(self, docstring, config=None):
orig_docstring = docstring
- docstring = textwrap.dedent(docstring).split('\n')
+ docstring = textwrap.dedent(docstring).split("\n")
self._doc = Reader(docstring)
self._parsed_data = copy.deepcopy(self.sections)
@@ -172,15 +172,17 @@ class NumpyDocString(Mapping):
l1 = self._doc.peek().strip() # e.g. Parameters
- if l1.startswith('.. index::'):
+ if l1.startswith(".. index::"):
return True
l2 = self._doc.peek(1).strip() # ---------- or ==========
- if len(l2) >= 3 and (set(l2) in ({'-'}, {'='}) ) and len(l2) != len(l1):
- snip = '\n'.join(self._doc._str[:2])+'...'
- self._error_location("potentially wrong underline length... \n%s \n%s in \n%s"\
- % (l1, l2, snip), error=False)
- return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1))
+ if len(l2) >= 3 and (set(l2) in ({"-"}, {"="})) and len(l2) != len(l1):
+ snip = "\n".join(self._doc._str[:2]) + "..."
+ self._error_location(
+ f"potentially wrong underline length... \n{l1} \n{l2} in \n{snip}",
+ error=False,
+ )
+ return l2.startswith("-" * len(l1)) or l2.startswith("=" * len(l1))
def _strip(self, doc):
i = 0
@@ -193,14 +195,14 @@ class NumpyDocString(Mapping):
if line.strip():
break
- return doc[i:len(doc)-j]
+ return doc[i : len(doc) - j]
def _read_to_next_section(self):
section = self._doc.read_to_next_empty_line()
while not self._is_at_section() and not self._doc.eof():
if not self._doc.peek(-1).strip(): # previous line was empty
- section += ['']
+ section += [""]
section += self._doc.read_to_next_empty_line()
@@ -211,7 +213,7 @@ class NumpyDocString(Mapping):
data = self._read_to_next_section()
name = data[0].strip()
- if name.startswith('..'): # index section
+ if name.startswith(".."): # index section
yield name, data[1:]
elif len(data) < 2:
yield StopIteration
@@ -224,14 +226,14 @@ class NumpyDocString(Mapping):
params = []
while not r.eof():
header = r.read().strip()
- if ' :' in header:
- arg_name, arg_type = header.split(' :', maxsplit=1)
+ if " :" in header:
+ arg_name, arg_type = header.split(" :", maxsplit=1)
arg_name, arg_type = arg_name.strip(), arg_type.strip()
else:
if single_element_is_type:
- arg_name, arg_type = '', header
+ arg_name, arg_type = "", header
else:
- arg_name, arg_type = header, ''
+ arg_name, arg_type = header, ""
desc = r.read_to_next_unindented_line()
desc = dedent_lines(desc)
@@ -261,21 +263,24 @@ class NumpyDocString(Mapping):
_funcbacktick = r"`(?P<name>(?:~\w+\.)?[a-zA-Z0-9_\.-]+)`"
_funcplain = r"(?P<name2>[a-zA-Z0-9_\.-]+)"
_funcname = r"(" + _role + _funcbacktick + r"|" + _funcplain + r")"
- _funcnamenext = _funcname.replace('role', 'rolenext')
- _funcnamenext = _funcnamenext.replace('name', 'namenext')
+ _funcnamenext = _funcname.replace("role", "rolenext")
+ _funcnamenext = _funcnamenext.replace("name", "namenext")
_description = r"(?P<description>\s*:(\s+(?P<desc>\S+.*))?)?\s*$"
_func_rgx = re.compile(r"^\s*" + _funcname + r"\s*")
_line_rgx = re.compile(
- r"^\s*" +
- r"(?P<allfuncs>" + # group for all function names
- _funcname +
- r"(?P<morefuncs>([,]\s+" + _funcnamenext + r")*)" +
- r")" + # end of "allfuncs"
- r"(?P<trailing>[,\.])?" + # Some function lists have a trailing comma (or period) '\s*'
- _description)
+ r"^\s*"
+ + r"(?P<allfuncs>"
+ + _funcname # group for all function names
+ + r"(?P<morefuncs>([,]\s+"
+ + _funcnamenext
+ + r")*)"
+ + r")"
+ + r"(?P<trailing>[,\.])?" # end of "allfuncs"
+ + _description # Some function lists have a trailing comma (or period) '\s*'
+ )
# Empty <DESC> elements are replaced with '..'
- empty_description = '..'
+ empty_description = ".."
def _parse_see_also(self, content):
"""
@@ -295,8 +300,8 @@ class NumpyDocString(Mapping):
m = self._func_rgx.match(text)
if not m:
self._error_location(f"Error parsing See Also entry {line!r}")
- role = m.group('role')
- name = m.group('name') if role else m.group('name2')
+ role = m.group("role")
+ name = m.group("name") if role else m.group("name2")
return name, role, m.end()
rest = []
@@ -307,24 +312,25 @@ class NumpyDocString(Mapping):
line_match = self._line_rgx.match(line)
description = None
if line_match:
- description = line_match.group('desc')
- if line_match.group('trailing') and description:
+ description = line_match.group("desc")
+ if line_match.group("trailing") and description:
self._error_location(
- 'Unexpected comma or period after function list at index %d of '
- 'line "%s"' % (line_match.end('trailing'), line),
- error=False)
- if not description and line.startswith(' '):
+ "Unexpected comma or period after function list at index %d of "
+ 'line "%s"' % (line_match.end("trailing"), line),
+ error=False,
+ )
+ if not description and line.startswith(" "):
rest.append(line.strip())
elif line_match:
funcs = []
- text = line_match.group('allfuncs')
+ text = line_match.group("allfuncs")
while True:
if not text.strip():
break
name, role, match_end = parse_item_name(text)
funcs.append((name, role))
text = text[match_end:].strip()
- if text and text[0] == ',':
+ if text and text[0] == ",":
text = text[1:].strip()
rest = list(filter(None, [description]))
items.append((funcs, rest))
@@ -338,17 +344,18 @@ class NumpyDocString(Mapping):
:refguide: something, else, and more
"""
+
def strip_each_in(lst):
return [s.strip() for s in lst]
out = {}
- section = section.split('::')
+ section = section.split("::")
if len(section) > 1:
- out['default'] = strip_each_in(section[1].split(','))[0]
+ out["default"] = strip_each_in(section[1].split(","))[0]
for line in content:
- line = line.split(':')
+ line = line.split(":")
if len(line) > 2:
- out[line[1]] = strip_each_in(line[2].split(','))
+ out[line[1]] = strip_each_in(line[2].split(","))
return out
def _parse_summary(self):
@@ -360,18 +367,18 @@ class NumpyDocString(Mapping):
while True:
summary = self._doc.read_to_next_empty_line()
summary_str = " ".join([s.strip() for s in summary]).strip()
- compiled = re.compile(r'^([\w., ]+=)?\s*[\w\.]+\(.*\)$')
+ compiled = re.compile(r"^([\w., ]+=)?\s*[\w\.]+\(.*\)$")
if compiled.match(summary_str):
- self['Signature'] = summary_str
+ self["Signature"] = summary_str
if not self._is_at_section():
continue
break
if summary is not None:
- self['Summary'] = summary
+ self["Summary"] = summary
if not self._is_at_section():
- self['Extended Summary'] = self._read_to_next_section()
+ self["Extended Summary"] = self._read_to_next_section()
def _parse(self):
self._doc.reset()
@@ -380,42 +387,44 @@ class NumpyDocString(Mapping):
sections = list(self._read_sections())
section_names = {section for section, content in sections}
- has_returns = 'Returns' in section_names
- has_yields = 'Yields' in section_names
+ has_returns = "Returns" in section_names
+ has_yields = "Yields" in section_names
# We could do more tests, but we are not. Arbitrarily.
if has_returns and has_yields:
- msg = 'Docstring contains both a Returns and Yields section.'
+ msg = "Docstring contains both a Returns and Yields section."
raise ValueError(msg)
- if not has_yields and 'Receives' in section_names:
- msg = 'Docstring contains a Receives section but not Yields.'
+ if not has_yields and "Receives" in section_names:
+ msg = "Docstring contains a Receives section but not Yields."
raise ValueError(msg)
for (section, content) in sections:
- if not section.startswith('..'):
- section = (s.capitalize() for s in section.split(' '))
- section = ' '.join(section)
+ if not section.startswith(".."):
+ section = (s.capitalize() for s in section.split(" "))
+ section = " ".join(section)
if self.get(section):
- self._error_location("The section %s appears twice in %s"
- % (section, '\n'.join(self._doc._str)))
+ self._error_location(
+ "The section %s appears twice in %s"
+ % (section, "\n".join(self._doc._str))
+ )
- if section in ('Parameters', 'Other Parameters', 'Attributes',
- 'Methods'):
+ if section in ("Parameters", "Other Parameters", "Attributes", "Methods"):
self[section] = self._parse_param_list(content)
- elif section in ('Returns', 'Yields', 'Raises', 'Warns', 'Receives'):
+ elif section in ("Returns", "Yields", "Raises", "Warns", "Receives"):
self[section] = self._parse_param_list(
- content, single_element_is_type=True)
- elif section.startswith('.. index::'):
- self['index'] = self._parse_index(section, content)
- elif section == 'See Also':
- self['See Also'] = self._parse_see_also(content)
+ content, single_element_is_type=True
+ )
+ elif section.startswith(".. index::"):
+ self["index"] = self._parse_index(section, content)
+ elif section == "See Also":
+ self["See Also"] = self._parse_see_also(content)
else:
self[section] = content
@property
def _obj(self):
- if hasattr(self, '_cls'):
+ if hasattr(self, "_cls"):
return self._cls
- elif hasattr(self, '_f'):
+ elif hasattr(self, "_f"):
return self._f
return None
@@ -428,9 +437,9 @@ class NumpyDocString(Mapping):
filename = None
# Make UserWarning more descriptive via object introspection.
# Skip if introspection fails
- name = getattr(self._obj, '__name__', None)
+ name = getattr(self._obj, "__name__", None)
if name is None:
- name = getattr(getattr(self._obj, '__class__', None), '__name__', None)
+ name = getattr(getattr(self._obj, "__class__", None), "__name__", None)
if name is not None:
msg += f" in the docstring of {name}"
msg += f" in {filename}." if filename else ""
@@ -441,25 +450,25 @@ class NumpyDocString(Mapping):
# string conversion routines
- def _str_header(self, name, symbol='-'):
- return [name, len(name)*symbol]
+ def _str_header(self, name, symbol="-"):
+ return [name, len(name) * symbol]
def _str_indent(self, doc, indent=4):
- return [' '*indent + line for line in doc]
+ return [" " * indent + line for line in doc]
def _str_signature(self):
- if self['Signature']:
- return [self['Signature'].replace('*', r'\*')] + ['']
- return ['']
+ if self["Signature"]:
+ return [self["Signature"].replace("*", r"\*")] + [""]
+ return [""]
def _str_summary(self):
- if self['Summary']:
- return self['Summary'] + ['']
+ if self["Summary"]:
+ return self["Summary"] + [""]
return []
def _str_extended_summary(self):
- if self['Extended Summary']:
- return self['Extended Summary'] + ['']
+ if self["Extended Summary"]:
+ return self["Extended Summary"] + [""]
return []
def _str_param_list(self, name):
@@ -472,10 +481,10 @@ class NumpyDocString(Mapping):
parts.append(param.name)
if param.type:
parts.append(param.type)
- out += [' : '.join(parts)]
- if param.desc and ''.join(param.desc).strip():
+ out += [" : ".join(parts)]
+ if param.desc and "".join(param.desc).strip():
out += self._str_indent(param.desc)
- out += ['']
+ out += [""]
return out
def _str_section(self, name):
@@ -483,74 +492,81 @@ class NumpyDocString(Mapping):
if self[name]:
out += self._str_header(name)
out += self[name]
- out += ['']
+ out += [""]
return out
def _str_see_also(self, func_role):
- if not self['See Also']:
+ if not self["See Also"]:
return []
out = []
out += self._str_header("See Also")
- out += ['']
+ out += [""]
last_had_desc = True
- for funcs, desc in self['See Also']:
+ for funcs, desc in self["See Also"]:
assert isinstance(funcs, list)
links = []
for func, role in funcs:
if role:
- link = f':{role}:`{func}`'
+ link = f":{role}:`{func}`"
elif func_role:
- link = f':{func_role}:`{func}`'
+ link = f":{func_role}:`{func}`"
else:
link = f"`{func}`_"
links.append(link)
- link = ', '.join(links)
+ link = ", ".join(links)
out += [link]
if desc:
- out += self._str_indent([' '.join(desc)])
+ out += self._str_indent([" ".join(desc)])
last_had_desc = True
else:
last_had_desc = False
out += self._str_indent([self.empty_description])
if last_had_desc:
- out += ['']
- out += ['']
+ out += [""]
+ out += [""]
return out
def _str_index(self):
- idx = self['index']
+ idx = self["index"]
out = []
output_index = False
- default_index = idx.get('default', '')
+ default_index = idx.get("default", "")
if default_index:
output_index = True
- out += [f'.. index:: {default_index}']
+ out += [f".. index:: {default_index}"]
for section, references in idx.items():
- if section == 'default':
+ if section == "default":
continue
output_index = True
out += [f" :{section}: {', '.join(references)}"]
if output_index:
return out
- return ''
+ return ""
- def __str__(self, func_role=''):
+ def __str__(self, func_role=""):
out = []
out += self._str_signature()
out += self._str_summary()
out += self._str_extended_summary()
- for param_list in ('Parameters', 'Returns', 'Yields', 'Receives',
- 'Other Parameters', 'Raises', 'Warns'):
+ for param_list in (
+ "Parameters",
+ "Returns",
+ "Yields",
+ "Receives",
+ "Other Parameters",
+ "Raises",
+ "Warns",
+ ):
out += self._str_param_list(param_list)
- out += self._str_section('Warnings')
+ out += self._str_section("Warnings")
out += self._str_see_also(func_role)
- for s in ('Notes', 'References', 'Examples'):
+ for s in ("Notes", "References", "Examples"):
out += self._str_section(s)
- for param_list in ('Attributes', 'Methods'):
+ for param_list in ("Attributes", "Methods"):
out += self._str_param_list(param_list)
out += self._str_index()
- return '\n'.join(out)
+ return "\n".join(out)
def dedent_lines(lines):
@@ -559,33 +575,32 @@ def dedent_lines(lines):
class FunctionDoc(NumpyDocString):
- def __init__(self, func, role='func', doc=None, config=None):
+ def __init__(self, func, role="func", doc=None, config=None):
self._f = func
self._role = role # e.g. "func" or "meth"
if doc is None:
if func is None:
raise ValueError("No function or docstring given")
- doc = inspect.getdoc(func) or ''
+ doc = inspect.getdoc(func) or ""
if config is None:
config = {}
NumpyDocString.__init__(self, doc, config)
def get_func(self):
- func_name = getattr(self._f, '__name__', self.__class__.__name__)
+ func_name = getattr(self._f, "__name__", self.__class__.__name__)
if inspect.isclass(self._f):
- func = getattr(self._f, '__call__', self._f.__init__)
+ func = getattr(self._f, "__call__", self._f.__init__)
else:
func = self._f
return func, func_name
def __str__(self):
- out = ''
+ out = ""
func, func_name = self.get_func()
- roles = {'func': 'function',
- 'meth': 'method'}
+ roles = {"func": "function", "meth": "method"}
if self._role:
if self._role not in roles:
@@ -606,26 +621,24 @@ class ObjDoc(NumpyDocString):
class ClassDoc(NumpyDocString):
- extra_public_methods = ['__call__']
+ extra_public_methods = ["__call__"]
- def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc,
- config=None):
+ def __init__(self, cls, doc=None, modulename="", func_doc=FunctionDoc, config=None):
if not inspect.isclass(cls) and cls is not None:
raise ValueError(f"Expected a class or None, but got {cls!r}")
self._cls = cls
- if 'sphinx' in sys.modules:
+ if "sphinx" in sys.modules:
from sphinx.ext.autodoc import ALL
else:
ALL = object()
if config is None:
config = {}
- self.show_inherited_members = config.get(
- 'show_inherited_class_members', True)
+ self.show_inherited_members = config.get("show_inherited_class_members", True)
- if modulename and not modulename.endswith('.'):
- modulename += '.'
+ if modulename and not modulename.endswith("."):
+ modulename += "."
self._mod = modulename
if doc is None:
@@ -635,29 +648,31 @@ class ClassDoc(NumpyDocString):
NumpyDocString.__init__(self, doc)
- _members = config.get('members', [])
+ _members = config.get("members", [])
if _members is ALL:
_members = None
- _exclude = config.get('exclude-members', [])
+ _exclude = config.get("exclude-members", [])
+
+ if config.get("show_class_members", True) and _exclude is not ALL:
- if config.get('show_class_members', True) and _exclude is not ALL:
def splitlines_x(s):
if not s:
return []
else:
return s.splitlines()
- for field, items in [('Methods', self.methods),
- ('Attributes', self.properties)]:
+
+ for field, items in [
+ ("Methods", self.methods),
+ ("Attributes", self.properties),
+ ]:
if not self[field]:
doc_list = []
for name in sorted(items):
- if (name in _exclude or
- (_members and name not in _members)):
+ if name in _exclude or (_members and name not in _members):
continue
try:
doc_item = pydoc.getdoc(getattr(self._cls, name))
- doc_list.append(
- Parameter(name, '', splitlines_x(doc_item)))
+ doc_list.append(Parameter(name, "", splitlines_x(doc_item)))
except AttributeError:
pass # method doesn't exist
self[field] = doc_list
@@ -666,21 +681,33 @@ class ClassDoc(NumpyDocString):
def methods(self):
if self._cls is None:
return []
- return [name for name, func in inspect.getmembers(self._cls)
- if ((not name.startswith('_')
- or name in self.extra_public_methods)
- and isinstance(func, Callable)
- and self._is_show_member(name))]
+ return [
+ name
+ for name, func in inspect.getmembers(self._cls)
+ if (
+ (not name.startswith("_") or name in self.extra_public_methods)
+ and isinstance(func, Callable)
+ and self._is_show_member(name)
+ )
+ ]
@property
def properties(self):
if self._cls is None:
return []
- return [name for name, func in inspect.getmembers(self._cls)
- if (not name.startswith('_') and
- (func is None or isinstance(func, property) or
- inspect.isdatadescriptor(func))
- and self._is_show_member(name))]
+ return [
+ name
+ for name, func in inspect.getmembers(self._cls)
+ if (
+ not name.startswith("_")
+ and (
+ func is None
+ or isinstance(func, property)
+ or inspect.isdatadescriptor(func)
+ )
+ and self._is_show_member(name)
+ )
+ ]
def _is_show_member(self, name):
if self.show_inherited_members:
@@ -693,19 +720,19 @@ class ClassDoc(NumpyDocString):
def get_doc_object(obj, what=None, doc=None, config=None):
if what is None:
if inspect.isclass(obj):
- what = 'class'
+ what = "class"
elif inspect.ismodule(obj):
- what = 'module'
+ what = "module"
elif isinstance(obj, Callable):
- what = 'function'
+ what = "function"
else:
- what = 'object'
+ what = "object"
if config is None:
config = {}
- if what == 'class':
+ if what == "class":
return ClassDoc(obj, func_doc=FunctionDoc, doc=doc, config=config)
- elif what in ('function', 'method'):
+ elif what in ("function", "method"):
return FunctionDoc(obj, doc=doc, config=config)
else:
if doc is None:
diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py
index b15afd2..ee8e093 100644
--- a/numpydoc/docscrape_sphinx.py
+++ b/numpydoc/docscrape_sphinx.py
@@ -14,7 +14,7 @@ from .docscrape import NumpyDocString, FunctionDoc, ClassDoc, ObjDoc
from .xref import make_xref
-IMPORT_MATPLOTLIB_RE = r'\b(import +matplotlib|from +matplotlib +import)\b'
+IMPORT_MATPLOTLIB_RE = r"\b(import +matplotlib|from +matplotlib +import)\b"
class SphinxDocString(NumpyDocString):
@@ -25,77 +25,76 @@ class SphinxDocString(NumpyDocString):
self.load_config(config)
def load_config(self, config):
- self.use_plots = config.get('use_plots', False)
- self.use_blockquotes = config.get('use_blockquotes', False)
- self.class_members_toctree = config.get('class_members_toctree', True)
- self.attributes_as_param_list = config.get('attributes_as_param_list', True)
- self.xref_param_type = config.get('xref_param_type', False)
- self.xref_aliases = config.get('xref_aliases', dict())
- self.xref_ignore = config.get('xref_ignore', set())
- self.template = config.get('template', None)
+ self.use_plots = config.get("use_plots", False)
+ self.use_blockquotes = config.get("use_blockquotes", False)
+ self.class_members_toctree = config.get("class_members_toctree", True)
+ self.attributes_as_param_list = config.get("attributes_as_param_list", True)
+ self.xref_param_type = config.get("xref_param_type", False)
+ self.xref_aliases = config.get("xref_aliases", dict())
+ self.xref_ignore = config.get("xref_ignore", set())
+ self.template = config.get("template", None)
if self.template is None:
- template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')]
+ template_dirs = [os.path.join(os.path.dirname(__file__), "templates")]
template_loader = FileSystemLoader(template_dirs)
template_env = SandboxedEnvironment(loader=template_loader)
- self.template = template_env.get_template('numpydoc_docstring.rst')
+ self.template = template_env.get_template("numpydoc_docstring.rst")
# string conversion routines
- def _str_header(self, name, symbol='`'):
- return ['.. rubric:: ' + name, '']
+ def _str_header(self, name, symbol="`"):
+ return [".. rubric:: " + name, ""]
def _str_field_list(self, name):
- return [':' + name + ':']
+ return [":" + name + ":"]
def _str_indent(self, doc, indent=4):
out = []
for line in doc:
- out += [' '*indent + line]
+ out += [" " * indent + line]
return out
def _str_signature(self):
- return ['']
+ return [""]
def _str_summary(self):
- return self['Summary'] + ['']
+ return self["Summary"] + [""]
def _str_extended_summary(self):
- return self['Extended Summary'] + ['']
+ return self["Extended Summary"] + [""]
- def _str_returns(self, name='Returns'):
- named_fmt = '**%s** : %s'
- unnamed_fmt = '%s'
+ def _str_returns(self, name="Returns"):
+ named_fmt = "**%s** : %s"
+ unnamed_fmt = "%s"
out = []
if self[name]:
out += self._str_field_list(name)
- out += ['']
+ out += [""]
for param in self[name]:
param_type = param.type
if param_type and self.xref_param_type:
param_type = make_xref(
- param_type,
- self.xref_aliases,
- self.xref_ignore
+ param_type, self.xref_aliases, self.xref_ignore
)
if param.name:
- out += self._str_indent([named_fmt % (param.name.strip(),
- param_type)])
+ out += self._str_indent(
+ [named_fmt % (param.name.strip(), param_type)]
+ )
else:
out += self._str_indent([unnamed_fmt % param_type.strip()])
if not param.desc:
- out += self._str_indent(['..'], 8)
+ out += self._str_indent([".."], 8)
else:
if self.use_blockquotes:
- out += ['']
+ out += [""]
out += self._str_indent(param.desc, 8)
- out += ['']
+ out += [""]
return out
def _escape_args_and_kwargs(self, name):
- if name[:2] == '**':
- return r'\*\*' + name[2:]
- elif name[:1] == '*':
- return r'\*' + name[1:]
+ if name[:2] == "**":
+ return r"\*\*" + name[2:]
+ elif name[:1] == "*":
+ return r"\*" + name[1:]
else:
return name
@@ -138,42 +137,43 @@ class SphinxDocString(NumpyDocString):
# XXX: If changing the following, please check the rendering when param
# ends with '_', e.g. 'word_'
# See https://github.com/numpy/numpydoc/pull/144
- display_param = f'**{param}**'
+ display_param = f"**{param}**"
if not fake_autosummary:
return display_param, desc
param_obj = getattr(self._obj, param, None)
- if not (callable(param_obj)
- or isinstance(param_obj, property)
- or inspect.isgetsetdescriptor(param_obj)
- or inspect.ismemberdescriptor(param_obj)):
+ if not (
+ callable(param_obj)
+ or isinstance(param_obj, property)
+ or inspect.isgetsetdescriptor(param_obj)
+ or inspect.ismemberdescriptor(param_obj)
+ ):
param_obj = None
obj_doc = pydoc.getdoc(param_obj)
if not (param_obj and obj_doc):
return display_param, desc
- prefix = getattr(self, '_name', '')
+ prefix = getattr(self, "_name", "")
if prefix:
- link_prefix = f'{prefix}.'
+ link_prefix = f"{prefix}."
else:
- link_prefix = ''
+ link_prefix = ""
# Referenced object has a docstring
- display_param = f':obj:`{param} <{link_prefix}{param}>`'
+ display_param = f":obj:`{param} <{link_prefix}{param}>`"
if obj_doc:
# Overwrite desc. Take summary logic of autosummary
- desc = re.split(r'\n\s*\n', obj_doc.strip(), 1)[0]
+ desc = re.split(r"\n\s*\n", obj_doc.strip(), 1)[0]
# XXX: Should this have DOTALL?
# It does not in autosummary
- m = re.search(r"^([A-Z].*?\.)(?:\s|$)",
- ' '.join(desc.split()))
+ m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(desc.split()))
if m:
desc = m.group(1).strip()
else:
- desc = desc.partition('\n')[0]
- desc = desc.split('\n')
+ desc = desc.partition("\n")[0]
+ desc = desc.split("\n")
return display_param, desc
def _str_param_list(self, name, fake_autosummary=False):
@@ -199,11 +199,11 @@ class SphinxDocString(NumpyDocString):
out = []
if self[name]:
out += self._str_field_list(name)
- out += ['']
+ out += [""]
for param in self[name]:
- display_param, desc = self._process_param(param.name,
- param.desc,
- fake_autosummary)
+ display_param, desc = self._process_param(
+ param.name, param.desc, fake_autosummary
+ )
parts = []
if display_param:
parts.append(display_param)
@@ -212,20 +212,18 @@ class SphinxDocString(NumpyDocString):
param_type = param.type
if self.xref_param_type:
param_type = make_xref(
- param_type,
- self.xref_aliases,
- self.xref_ignore
+ param_type, self.xref_aliases, self.xref_ignore
)
parts.append(param_type)
- out += self._str_indent([' : '.join(parts)])
+ out += self._str_indent([" : ".join(parts)])
if desc and self.use_blockquotes:
- out += ['']
+ out += [""]
elif not desc:
# empty definition
- desc = ['..']
+ desc = [".."]
out += self._str_indent(desc, 8)
- out += ['']
+ out += [""]
return out
@@ -237,11 +235,11 @@ class SphinxDocString(NumpyDocString):
"""
out = []
if self[name]:
- out += [f'.. rubric:: {name}', '']
- prefix = getattr(self, '_name', '')
+ out += [f".. rubric:: {name}", ""]
+ prefix = getattr(self, "_name", "")
if prefix:
- prefix = f'~{prefix}.'
+ prefix = f"~{prefix}."
autosum = []
others = []
@@ -250,9 +248,11 @@ class SphinxDocString(NumpyDocString):
# Check if the referenced member can have a docstring or not
param_obj = getattr(self._obj, param.name, None)
- if not (callable(param_obj)
- or isinstance(param_obj, property)
- or inspect.isdatadescriptor(param_obj)):
+ if not (
+ callable(param_obj)
+ or isinstance(param_obj, property)
+ or inspect.isdatadescriptor(param_obj)
+ ):
param_obj = None
if param_obj and pydoc.getdoc(param_obj):
@@ -262,25 +262,24 @@ class SphinxDocString(NumpyDocString):
others.append(param)
if autosum:
- out += ['.. autosummary::']
+ out += [".. autosummary::"]
if self.class_members_toctree:
- out += [' :toctree:']
- out += [''] + autosum
+ out += [" :toctree:"]
+ out += [""] + autosum
if others:
maxlen_0 = max(3, max(len(p.name) + 4 for p in others))
hdr = "=" * maxlen_0 + " " + "=" * 10
- fmt = '%%%ds %%s ' % (maxlen_0,)
- out += ['', '', hdr]
+ fmt = "%%%ds %%s " % (maxlen_0,)
+ out += ["", "", hdr]
for param in others:
name = "**" + param.name.strip() + "**"
- desc = " ".join(x.strip()
- for x in param.desc).strip()
+ desc = " ".join(x.strip() for x in param.desc).strip()
if param.type:
desc = f"({param.type}) {desc}"
out += [fmt % (name, desc)]
out += [hdr]
- out += ['']
+ out += [""]
return out
def _str_section(self, name):
@@ -289,103 +288,105 @@ class SphinxDocString(NumpyDocString):
out += self._str_header(name)
content = textwrap.dedent("\n".join(self[name])).split("\n")
out += content
- out += ['']
+ out += [""]
return out
def _str_see_also(self, func_role):
out = []
- if self['See Also']:
+ if self["See Also"]:
see_also = super()._str_see_also(func_role)
- out = ['.. seealso::', '']
+ out = [".. seealso::", ""]
out += self._str_indent(see_also[2:])
return out
def _str_warnings(self):
out = []
- if self['Warnings']:
- out = ['.. warning::', '']
- out += self._str_indent(self['Warnings'])
- out += ['']
+ if self["Warnings"]:
+ out = [".. warning::", ""]
+ out += self._str_indent(self["Warnings"])
+ out += [""]
return out
def _str_index(self):
- idx = self['index']
+ idx = self["index"]
out = []
if len(idx) == 0:
return out
out += [f".. index:: {idx.get('default', '')}"]
for section, references in idx.items():
- if section == 'default':
+ if section == "default":
continue
- elif section == 'refguide':
+ elif section == "refguide":
out += [f" single: {', '.join(references)}"]
else:
out += [f" {section}: {','.join(references)}"]
- out += ['']
+ out += [""]
return out
def _str_references(self):
out = []
- if self['References']:
- out += self._str_header('References')
- if isinstance(self['References'], str):
- self['References'] = [self['References']]
- out.extend(self['References'])
- out += ['']
+ if self["References"]:
+ out += self._str_header("References")
+ if isinstance(self["References"], str):
+ self["References"] = [self["References"]]
+ out.extend(self["References"])
+ out += [""]
# Latex collects all references to a separate bibliography,
# so we need to insert links to it
- out += ['.. only:: latex', '']
+ out += [".. only:: latex", ""]
items = []
- for line in self['References']:
- m = re.match(r'.. \[([a-z0-9._-]+)\]', line, re.I)
+ for line in self["References"]:
+ m = re.match(r".. \[([a-z0-9._-]+)\]", line, re.I)
if m:
items.append(m.group(1))
- out += [' ' + ", ".join([f"[{item}]_" for item in items]), '']
+ out += [" " + ", ".join([f"[{item}]_" for item in items]), ""]
return out
def _str_examples(self):
- examples_str = "\n".join(self['Examples'])
+ examples_str = "\n".join(self["Examples"])
- if (self.use_plots and re.search(IMPORT_MATPLOTLIB_RE, examples_str)
- and 'plot::' not in examples_str):
+ if (
+ self.use_plots
+ and re.search(IMPORT_MATPLOTLIB_RE, examples_str)
+ and "plot::" not in examples_str
+ ):
out = []
- out += self._str_header('Examples')
- out += ['.. plot::', '']
- out += self._str_indent(self['Examples'])
- out += ['']
+ out += self._str_header("Examples")
+ out += [".. plot::", ""]
+ out += self._str_indent(self["Examples"])
+ out += [""]
return out
else:
- return self._str_section('Examples')
+ return self._str_section("Examples")
def __str__(self, indent=0, func_role="obj"):
ns = {
- 'signature': self._str_signature(),
- 'index': self._str_index(),
- 'summary': self._str_summary(),
- 'extended_summary': self._str_extended_summary(),
- 'parameters': self._str_param_list('Parameters'),
- 'returns': self._str_returns('Returns'),
- 'yields': self._str_returns('Yields'),
- 'receives': self._str_returns('Receives'),
- 'other_parameters': self._str_param_list('Other Parameters'),
- 'raises': self._str_returns('Raises'),
- 'warns': self._str_returns('Warns'),
- 'warnings': self._str_warnings(),
- 'see_also': self._str_see_also(func_role),
- 'notes': self._str_section('Notes'),
- 'references': self._str_references(),
- 'examples': self._str_examples(),
- 'attributes':
- self._str_param_list('Attributes', fake_autosummary=True)
- if self.attributes_as_param_list
- else self._str_member_list('Attributes'),
- 'methods': self._str_member_list('Methods'),
+ "signature": self._str_signature(),
+ "index": self._str_index(),
+ "summary": self._str_summary(),
+ "extended_summary": self._str_extended_summary(),
+ "parameters": self._str_param_list("Parameters"),
+ "returns": self._str_returns("Returns"),
+ "yields": self._str_returns("Yields"),
+ "receives": self._str_returns("Receives"),
+ "other_parameters": self._str_param_list("Other Parameters"),
+ "raises": self._str_returns("Raises"),
+ "warns": self._str_returns("Warns"),
+ "warnings": self._str_warnings(),
+ "see_also": self._str_see_also(func_role),
+ "notes": self._str_section("Notes"),
+ "references": self._str_references(),
+ "examples": self._str_examples(),
+ "attributes": self._str_param_list("Attributes", fake_autosummary=True)
+ if self.attributes_as_param_list
+ else self._str_member_list("Attributes"),
+ "methods": self._str_member_list("Methods"),
}
- ns = {k: '\n'.join(v) for k, v in ns.items()}
+ ns = {k: "\n".join(v) for k, v in ns.items()}
rendered = self.template.render(**ns)
- return '\n'.join(self._str_indent(rendered.split('\n'), indent))
+ return "\n".join(self._str_indent(rendered.split("\n"), indent))
class SphinxFunctionDoc(SphinxDocString, FunctionDoc):
@@ -416,29 +417,28 @@ class SphinxObjDoc(SphinxDocString, ObjDoc):
def get_doc_object(obj, what=None, doc=None, config=None, builder=None):
if what is None:
if inspect.isclass(obj):
- what = 'class'
+ what = "class"
elif inspect.ismodule(obj):
- what = 'module'
+ what = "module"
elif isinstance(obj, Callable):
- what = 'function'
+ what = "function"
else:
- what = 'object'
+ what = "object"
if config is None:
config = {}
- template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')]
+ template_dirs = [os.path.join(os.path.dirname(__file__), "templates")]
if builder is not None:
template_loader = BuiltinTemplateLoader()
template_loader.init(builder, dirs=template_dirs)
else:
template_loader = FileSystemLoader(template_dirs)
template_env = SandboxedEnvironment(loader=template_loader)
- config['template'] = template_env.get_template('numpydoc_docstring.rst')
+ config["template"] = template_env.get_template("numpydoc_docstring.rst")
- if what == 'class':
- return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc,
- config=config)
- elif what in ('function', 'method'):
+ if what == "class":
+ return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, config=config)
+ elif what in ("function", "method"):
return SphinxFunctionDoc(obj, doc=doc, config=config)
else:
if doc is None:
diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py
index 1775a7b..8210006 100644
--- a/numpydoc/numpydoc.py
+++ b/numpydoc/numpydoc.py
@@ -30,7 +30,7 @@ from sphinx.addnodes import pending_xref, desc_content
from sphinx.util import logging
from sphinx.errors import ExtensionError
-if sphinx.__version__ < '3.0':
+if sphinx.__version__ < "3.0":
raise RuntimeError("Sphinx 3.0 or newer is required")
from .docscrape_sphinx import get_doc_object
@@ -42,31 +42,28 @@ logger = logging.getLogger(__name__)
HASH_LEN = 12
+
def rename_references(app, what, name, obj, options, lines):
# decorate reference numbers so that there are no duplicates
# these are later undecorated in the doctree, in relabel_references
references = set()
for line in lines:
line = line.strip()
- m = re.match(r'^\.\. +\[(%s)\]' %
- app.config.numpydoc_citation_re,
- line, re.I)
+ m = re.match(r"^\.\. +\[(%s)\]" % app.config.numpydoc_citation_re, line, re.I)
if m:
references.add(m.group(1))
if references:
# we use a hash to mangle the reference name to avoid invalid names
sha = hashlib.sha256()
- sha.update(name.encode('utf8'))
- prefix = 'R' + sha.hexdigest()[:HASH_LEN]
+ sha.update(name.encode("utf8"))
+ prefix = "R" + sha.hexdigest()[:HASH_LEN]
for r in references:
- new_r = prefix + '-' + r
+ new_r = prefix + "-" + r
for i, line in enumerate(lines):
- lines[i] = lines[i].replace(f'[{r}]_',
- f'[{new_r}]_')
- lines[i] = lines[i].replace(f'.. [{r}]',
- f'.. [{new_r}]')
+ lines[i] = lines[i].replace(f"[{r}]_", f"[{new_r}]_")
+ lines[i] = lines[i].replace(f".. [{r}]", f".. [{new_r}]")
def _is_cite_in_numpydoc_docstring(citation_node):
@@ -83,10 +80,11 @@ def _is_cite_in_numpydoc_docstring(citation_node):
if section_node is None:
return False
- sibling_sections = itertools.chain(section_node.traverse(is_docstring_section,
- include_self=True,
- descend=False,
- siblings=True))
+ sibling_sections = itertools.chain(
+ section_node.traverse(
+ is_docstring_section, include_self=True, descend=False, siblings=True
+ )
+ )
for sibling_section in sibling_sections:
if not sibling_section.children:
continue
@@ -107,22 +105,24 @@ def relabel_references(app, doc):
if not _is_cite_in_numpydoc_docstring(citation_node):
continue
label_node = citation_node[0]
- prefix, _, new_label = label_node[0].astext().partition('-')
+ prefix, _, new_label = label_node[0].astext().partition("-")
assert len(prefix) == HASH_LEN + 1
new_text = Text(new_label)
label_node.replace(label_node[0], new_text)
- for id_ in citation_node['backrefs']:
+ for id_ in citation_node["backrefs"]:
ref = doc.ids[id_]
ref_text = ref[0]
# Sphinx has created pending_xref nodes with [reftext] text.
def matching_pending_xref(node):
- return (isinstance(node, pending_xref) and
- node[0].astext() == f'[{ref_text}]')
+ return (
+ isinstance(node, pending_xref)
+ and node[0].astext() == f"[{ref_text}]"
+ )
for xref_node in ref.parent.traverse(matching_pending_xref):
- xref_node.replace(xref_node[0], Text(f'[{new_text}]'))
+ xref_node.replace(xref_node[0], Text(f"[{new_text}]"))
ref.replace(ref_text, new_text.copy())
@@ -130,48 +130,49 @@ def clean_backrefs(app, doc, docname):
# only::latex directive has resulted in citation backrefs without reference
known_ref_ids = set()
for ref in doc.traverse(reference, descend=True):
- for id_ in ref['ids']:
+ for id_ in ref["ids"]:
known_ref_ids.add(id_)
for citation_node in doc.traverse(citation, descend=True):
# remove backrefs to non-existent refs
- citation_node['backrefs'] = [id_ for id_ in citation_node['backrefs']
- if id_ in known_ref_ids]
+ citation_node["backrefs"] = [
+ id_ for id_ in citation_node["backrefs"] if id_ in known_ref_ids
+ ]
-DEDUPLICATION_TAG = ' !! processed by numpydoc !!'
+DEDUPLICATION_TAG = " !! processed by numpydoc !!"
def mangle_docstrings(app, what, name, obj, options, lines):
if DEDUPLICATION_TAG in lines:
return
- cfg = {'use_plots': app.config.numpydoc_use_plots,
- 'use_blockquotes': app.config.numpydoc_use_blockquotes,
- 'show_class_members': app.config.numpydoc_show_class_members,
- 'show_inherited_class_members':
- app.config.numpydoc_show_inherited_class_members,
- 'class_members_toctree': app.config.numpydoc_class_members_toctree,
- 'attributes_as_param_list':
- app.config.numpydoc_attributes_as_param_list,
- 'xref_param_type': app.config.numpydoc_xref_param_type,
- 'xref_aliases': app.config.numpydoc_xref_aliases_complete,
- 'xref_ignore': app.config.numpydoc_xref_ignore,
- }
+ cfg = {
+ "use_plots": app.config.numpydoc_use_plots,
+ "use_blockquotes": app.config.numpydoc_use_blockquotes,
+ "show_class_members": app.config.numpydoc_show_class_members,
+ "show_inherited_class_members": app.config.numpydoc_show_inherited_class_members,
+ "class_members_toctree": app.config.numpydoc_class_members_toctree,
+ "attributes_as_param_list": app.config.numpydoc_attributes_as_param_list,
+ "xref_param_type": app.config.numpydoc_xref_param_type,
+ "xref_aliases": app.config.numpydoc_xref_aliases_complete,
+ "xref_ignore": app.config.numpydoc_xref_ignore,
+ }
cfg.update(options or {})
- u_NL = '\n'
- if what == 'module':
+ u_NL = "\n"
+ if what == "module":
# Strip top title
- pattern = '^\\s*[#*=]{4,}\\n[a-z0-9 -]+\\n[#*=]{4,}\\s*'
+ pattern = "^\\s*[#*=]{4,}\\n[a-z0-9 -]+\\n[#*=]{4,}\\s*"
title_re = re.compile(pattern, re.I | re.S)
- lines[:] = title_re.sub('', u_NL.join(lines)).split(u_NL)
+ lines[:] = title_re.sub("", u_NL.join(lines)).split(u_NL)
else:
try:
- doc = get_doc_object(obj, what, u_NL.join(lines), config=cfg,
- builder=app.builder)
+ doc = get_doc_object(
+ obj, what, u_NL.join(lines), config=cfg, builder=app.builder
+ )
lines[:] = str(doc).split(u_NL)
except Exception:
- logger.error('[numpydoc] While processing docstring for %r', name)
+ logger.error("[numpydoc] While processing docstring for %r", name)
raise
if app.config.numpydoc_validation_checks:
@@ -195,33 +196,33 @@ def mangle_docstrings(app, what, name, obj, options, lines):
msg += f" {err[0]}: {err[1]}\n"
logger.warning(msg)
-
# call function to replace reference numbers so that there are no
# duplicates
rename_references(app, what, name, obj, options, lines)
- lines += ['..', DEDUPLICATION_TAG]
+ lines += ["..", DEDUPLICATION_TAG]
def mangle_signature(app, what, name, obj, options, sig, retann):
# Do not try to inspect classes that don't define `__init__`
- if (inspect.isclass(obj) and
- (not hasattr(obj, '__init__') or
- 'initializes x; see ' in pydoc.getdoc(obj.__init__))):
- return '', ''
+ if inspect.isclass(obj) and (
+ not hasattr(obj, "__init__")
+ or "initializes x; see " in pydoc.getdoc(obj.__init__)
+ ):
+ return "", ""
- if not (isinstance(obj, Callable) or
- hasattr(obj, '__argspec_is_invalid_')):
+ if not (isinstance(obj, Callable) or hasattr(obj, "__argspec_is_invalid_")):
return
- if not hasattr(obj, '__doc__'):
+ if not hasattr(obj, "__doc__"):
return
- doc = get_doc_object(obj, config={'show_class_members': False})
- sig = (doc['Signature']
- or _clean_text_signature(getattr(obj, '__text_signature__', None)))
+ doc = get_doc_object(obj, config={"show_class_members": False})
+ sig = doc["Signature"] or _clean_text_signature(
+ getattr(obj, "__text_signature__", None)
+ )
if sig:
sig = re.sub("^[^(]*", "", sig)
- return sig, ''
+ return sig, ""
def _clean_text_signature(sig):
@@ -231,43 +232,42 @@ def _clean_text_signature(sig):
start, end = start_pattern.search(sig).span()
start_sig = sig[start:end]
sig = sig[end:-1]
- sig = re.sub(r'^\$(self|module|type)(,\s|$)','' , sig, count=1)
- sig = re.sub(r'(^|(?<=,\s))/,\s\*', '*', sig, count=1)
- return start_sig + sig + ')'
+ sig = re.sub(r"^\$(self|module|type)(,\s|$)", "", sig, count=1)
+ sig = re.sub(r"(^|(?<=,\s))/,\s\*", "*", sig, count=1)
+ return start_sig + sig + ")"
def setup(app, get_doc_object_=get_doc_object):
- if not hasattr(app, 'add_config_value'):
+ if not hasattr(app, "add_config_value"):
return # probably called by nose, better bail out
global get_doc_object
get_doc_object = get_doc_object_
- app.setup_extension('sphinx.ext.autosummary')
- app.connect('config-inited', update_config)
- app.connect('autodoc-process-docstring', mangle_docstrings)
- app.connect('autodoc-process-signature', mangle_signature)
- app.connect('doctree-read', relabel_references)
- app.connect('doctree-resolved', clean_backrefs)
- app.add_config_value('numpydoc_use_plots', None, False)
- app.add_config_value('numpydoc_use_blockquotes', None, False)
- app.add_config_value('numpydoc_show_class_members', True, True)
- app.add_config_value('numpydoc_show_inherited_class_members', True, True)
- app.add_config_value('numpydoc_class_members_toctree', True, True)
- app.add_config_value('numpydoc_citation_re', '[a-z0-9_.-]+', True)
- app.add_config_value('numpydoc_attributes_as_param_list', True, True)
- app.add_config_value('numpydoc_xref_param_type', False, True)
- app.add_config_value('numpydoc_xref_aliases', dict(), True)
- app.add_config_value('numpydoc_xref_ignore', set(), True)
- app.add_config_value('numpydoc_validation_checks', set(), True)
- app.add_config_value('numpydoc_validation_exclude', set(), False)
+ app.setup_extension("sphinx.ext.autosummary")
+ app.connect("config-inited", update_config)
+ app.connect("autodoc-process-docstring", mangle_docstrings)
+ app.connect("autodoc-process-signature", mangle_signature)
+ app.connect("doctree-read", relabel_references)
+ app.connect("doctree-resolved", clean_backrefs)
+ app.add_config_value("numpydoc_use_plots", None, False)
+ app.add_config_value("numpydoc_use_blockquotes", None, False)
+ app.add_config_value("numpydoc_show_class_members", True, True)
+ app.add_config_value("numpydoc_show_inherited_class_members", True, True)
+ app.add_config_value("numpydoc_class_members_toctree", True, True)
+ app.add_config_value("numpydoc_citation_re", "[a-z0-9_.-]+", True)
+ app.add_config_value("numpydoc_attributes_as_param_list", True, True)
+ app.add_config_value("numpydoc_xref_param_type", False, True)
+ app.add_config_value("numpydoc_xref_aliases", dict(), True)
+ app.add_config_value("numpydoc_xref_ignore", set(), True)
+ app.add_config_value("numpydoc_validation_checks", set(), True)
+ app.add_config_value("numpydoc_validation_exclude", set(), False)
# Extra mangling domains
app.add_domain(NumpyPythonDomain)
app.add_domain(NumpyCDomain)
- metadata = {'version': __version__,
- 'parallel_read_safe': True}
+ metadata = {"version": __version__, "parallel_read_safe": True}
return metadata
@@ -332,31 +332,32 @@ class ManglingDomainBase:
def wrap_mangling_directives(self):
for name, objtype in list(self.directive_mangling_map.items()):
self.directives[name] = wrap_mangling_directive(
- self.directives[name], objtype)
+ self.directives[name], objtype
+ )
class NumpyPythonDomain(ManglingDomainBase, PythonDomain):
- name = 'np'
+ name = "np"
directive_mangling_map = {
- 'function': 'function',
- 'class': 'class',
- 'exception': 'class',
- 'method': 'function',
- 'classmethod': 'function',
- 'staticmethod': 'function',
- 'attribute': 'attribute',
+ "function": "function",
+ "class": "class",
+ "exception": "class",
+ "method": "function",
+ "classmethod": "function",
+ "staticmethod": "function",
+ "attribute": "attribute",
}
indices = []
class NumpyCDomain(ManglingDomainBase, CDomain):
- name = 'np-c'
+ name = "np-c"
directive_mangling_map = {
- 'function': 'function',
- 'member': 'attribute',
- 'macro': 'function',
- 'type': 'class',
- 'var': 'object',
+ "function": "function",
+ "member": "attribute",
+ "macro": "function",
+ "type": "class",
+ "var": "object",
}
@@ -412,7 +413,7 @@ def match_items(lines, content_old):
items_new.append(items_old[j])
if line.strip() and j < len(lines_old) - 1:
j += 1
- assert(len(items_new) == len(lines))
+ assert len(items_new) == len(lines)
return items_new
@@ -423,7 +424,7 @@ def wrap_mangling_directive(base_directive, objtype):
name = None
if self.arguments:
- m = re.match(r'^(.*\s+)?(.*?)(\(.*)?', self.arguments[0])
+ m = re.match(r"^(.*\s+)?(.*?)(\(.*)?", self.arguments[0])
name = m.group(2).strip()
if not name:
@@ -433,8 +434,7 @@ def wrap_mangling_directive(base_directive, objtype):
mangle_docstrings(env.app, objtype, name, None, None, lines)
if self.content:
items = match_items(lines, self.content)
- self.content = ViewList(lines, items=items,
- parent=self.content.parent)
+ self.content = ViewList(lines, items=items, parent=self.content.parent)
return base_directive.run(self)
diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py
index 9644008..01447a0 100644
--- a/numpydoc/tests/test_docscrape.py
+++ b/numpydoc/tests/test_docscrape.py
@@ -8,20 +8,19 @@ import jinja2
from numpydoc.numpydoc import update_config
from numpydoc.xref import DEFAULT_LINKS
-from numpydoc.docscrape import (
- NumpyDocString,
- FunctionDoc,
- ClassDoc,
- ParseError
+from numpydoc.docscrape import NumpyDocString, FunctionDoc, ClassDoc, ParseError
+from numpydoc.docscrape_sphinx import (
+ SphinxDocString,
+ SphinxClassDoc,
+ SphinxFunctionDoc,
+ get_doc_object,
)
-from numpydoc.docscrape_sphinx import (SphinxDocString, SphinxClassDoc,
- SphinxFunctionDoc, get_doc_object)
import pytest
from pytest import raises as assert_raises
from pytest import warns as assert_warns
-doc_txt = '''\
+doc_txt = """\
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
Draw values from a multivariate normal distribution with specified
@@ -131,11 +130,12 @@ doc_txt = '''\
.. index:: random
:refguide: random;distributions, random;gauss
- '''
+ """
-@pytest.fixture(params=['','\n '], ids=["flush", "newline_indented"])
+
+@pytest.fixture(params=["", "\n "], ids=["flush", "newline_indented"])
def doc(request):
- return NumpyDocString(request.param+doc_txt)
+ return NumpyDocString(request.param + doc_txt)
doc_yields_txt = """
@@ -173,92 +173,92 @@ doc_sent = NumpyDocString(doc_sent_txt)
def test_signature(doc):
- assert doc['Signature'].startswith('numpy.multivariate_normal(')
- assert doc['Signature'].endswith('spam=None)')
+ assert doc["Signature"].startswith("numpy.multivariate_normal(")
+ assert doc["Signature"].endswith("spam=None)")
def test_summary(doc):
- assert doc['Summary'][0].startswith('Draw values')
- assert doc['Summary'][-1].endswith('covariance.')
+ assert doc["Summary"][0].startswith("Draw values")
+ assert doc["Summary"][-1].endswith("covariance.")
def test_extended_summary(doc):
- assert doc['Extended Summary'][0].startswith('The multivariate normal')
+ assert doc["Extended Summary"][0].startswith("The multivariate normal")
def test_parameters(doc):
- assert len(doc['Parameters']) == 4
- names = [n for n, _, _ in doc['Parameters']]
- assert all(a == b for a, b in zip(names, ['mean', 'cov', 'shape']))
+ assert len(doc["Parameters"]) == 4
+ names = [n for n, _, _ in doc["Parameters"]]
+ assert all(a == b for a, b in zip(names, ["mean", "cov", "shape"]))
- arg, arg_type, desc = doc['Parameters'][1]
- assert arg_type == '(N, N) ndarray'
- assert desc[0].startswith('Covariance matrix')
- assert doc['Parameters'][0][-1][-1] == ' (1+2+3)/3'
+ arg, arg_type, desc = doc["Parameters"][1]
+ assert arg_type == "(N, N) ndarray"
+ assert desc[0].startswith("Covariance matrix")
+ assert doc["Parameters"][0][-1][-1] == " (1+2+3)/3"
- arg, arg_type, desc = doc['Parameters'][2]
- assert arg == 'shape'
- assert arg_type == 'tuple of ints'
- assert desc[0].startswith('Given')
- assert doc['Parameters'][0][-1][-1] == ' (1+2+3)/3'
+ arg, arg_type, desc = doc["Parameters"][2]
+ assert arg == "shape"
+ assert arg_type == "tuple of ints"
+ assert desc[0].startswith("Given")
+ assert doc["Parameters"][0][-1][-1] == " (1+2+3)/3"
- arg, arg_type, desc = doc['Parameters'][3]
- assert arg == 'dtype'
- assert arg_type == 'data type object, optional (default : float)'
- assert desc[0].startswith('The type and size')
+ arg, arg_type, desc = doc["Parameters"][3]
+ assert arg == "dtype"
+ assert arg_type == "data type object, optional (default : float)"
+ assert desc[0].startswith("The type and size")
def test_other_parameters(doc):
- assert len(doc['Other Parameters']) == 1
- assert [n for n, _, _ in doc['Other Parameters']] == ['spam']
- arg, arg_type, desc = doc['Other Parameters'][0]
- assert arg_type == 'parrot'
- assert desc[0].startswith('A parrot off its mortal coil')
-
+ assert len(doc["Other Parameters"]) == 1
+ assert [n for n, _, _ in doc["Other Parameters"]] == ["spam"]
+ arg, arg_type, desc = doc["Other Parameters"][0]
+ assert arg_type == "parrot"
+ assert desc[0].startswith("A parrot off its mortal coil")
def test_returns(doc):
- assert len(doc['Returns']) == 3
- arg, arg_type, desc = doc['Returns'][0]
- assert arg == 'out'
- assert arg_type == 'ndarray'
- assert desc[0].startswith('The drawn samples')
- assert desc[-1].endswith('distribution.')
+ assert len(doc["Returns"]) == 3
+ arg, arg_type, desc = doc["Returns"][0]
+ assert arg == "out"
+ assert arg_type == "ndarray"
+ assert desc[0].startswith("The drawn samples")
+ assert desc[-1].endswith("distribution.")
- arg, arg_type, desc = doc['Returns'][1]
- assert arg == ''
- assert arg_type == 'list of str'
- assert desc[0].startswith('This is not a real')
- assert desc[-1].endswith('anonymous return values.')
+ arg, arg_type, desc = doc["Returns"][1]
+ assert arg == ""
+ assert arg_type == "list of str"
+ assert desc[0].startswith("This is not a real")
+ assert desc[-1].endswith("anonymous return values.")
- arg, arg_type, desc = doc['Returns'][2]
- assert arg == ''
- assert arg_type == 'no_description'
- assert not ''.join(desc).strip()
+ arg, arg_type, desc = doc["Returns"][2]
+ assert arg == ""
+ assert arg_type == "no_description"
+ assert not "".join(desc).strip()
def test_yields():
- section = doc_yields['Yields']
+ section = doc_yields["Yields"]
assert len(section) == 3
- truth = [('a', 'int', 'apples.'),
- ('b', 'int', 'bananas.'),
- ('', 'int', 'unknowns.')]
+ truth = [
+ ("a", "int", "apples."),
+ ("b", "int", "bananas."),
+ ("", "int", "unknowns."),
+ ]
for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(section, truth):
assert arg == arg_
assert arg_type == arg_type_
- assert desc[0].startswith('The number of')
+ assert desc[0].startswith("The number of")
assert desc[0].endswith(end)
def test_sent():
- section = doc_sent['Receives']
+ section = doc_sent["Receives"]
assert len(section) == 2
- truth = [('b', 'int', 'bananas.'),
- ('c', 'int', 'oranges.')]
+ truth = [("b", "int", "bananas."), ("c", "int", "oranges.")]
for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(section, truth):
assert arg == arg_
assert arg_type == arg_type_
- assert desc[0].startswith('The number of')
+ assert desc[0].startswith("The number of")
assert desc[0].endswith(end)
@@ -311,6 +311,7 @@ That should break...
Second note.
"""
+
def spam(self, a, b):
"""Spam\n\nSpam spam."""
pass
@@ -340,40 +341,40 @@ That should break...
def test_notes(doc):
- assert doc['Notes'][0].startswith('Instead')
- assert doc['Notes'][-1].endswith('definite.')
- assert len(doc['Notes']) == 17
+ assert doc["Notes"][0].startswith("Instead")
+ assert doc["Notes"][-1].endswith("definite.")
+ assert len(doc["Notes"]) == 17
def test_references(doc):
- assert doc['References'][0].startswith('..')
- assert doc['References'][-1].endswith('2001.')
+ assert doc["References"][0].startswith("..")
+ assert doc["References"][-1].endswith("2001.")
def test_examples(doc):
- assert doc['Examples'][0].startswith('>>>')
- assert doc['Examples'][-1].endswith('True]')
+ assert doc["Examples"][0].startswith(">>>")
+ assert doc["Examples"][-1].endswith("True]")
def test_index(doc):
- assert doc['index']['default'] == 'random'
- assert len(doc['index']) == 2
- assert len(doc['index']['refguide']) == 2
+ assert doc["index"]["default"] == "random"
+ assert len(doc["index"]) == 2
+ assert len(doc["index"]["refguide"]) == 2
def _strip_blank_lines(s):
"Remove leading, trailing and multiple blank lines"
- s = re.sub(r'^\s*\n', '', s)
- s = re.sub(r'\n\s*$', '', s)
- s = re.sub(r'\n\s*\n', r'\n\n', s)
+ s = re.sub(r"^\s*\n", "", s)
+ s = re.sub(r"\n\s*$", "", s)
+ s = re.sub(r"\n\s*\n", r"\n\n", s)
return s
def line_by_line_compare(a, b, n_lines=None):
a = textwrap.dedent(a)
b = textwrap.dedent(b)
- a = [l.rstrip() for l in _strip_blank_lines(a).split('\n')][:n_lines]
- b = [l.rstrip() for l in _strip_blank_lines(b).split('\n')][:n_lines]
+ a = [l.rstrip() for l in _strip_blank_lines(a).split("\n")][:n_lines]
+ b = [l.rstrip() for l in _strip_blank_lines(b).split("\n")][:n_lines]
assert len(a) == len(b)
for ii, (aa, bb) in enumerate(zip(a, b)):
assert aa == bb
@@ -383,8 +384,9 @@ def test_str(doc):
# doc_txt has the order of Notes and See Also sections flipped.
# This should be handled automatically, and so, one thing this test does
# is to make sure that See Also precedes Notes in the output.
- line_by_line_compare(str(doc),
-"""numpy.multivariate_normal(mean, cov, shape=None, spam=None)
+ line_by_line_compare(
+ str(doc),
+ """numpy.multivariate_normal(mean, cov, shape=None, spam=None)
Draw values from a multivariate normal distribution with specified
mean and covariance.
@@ -494,12 +496,14 @@ standard deviation:
[True, True]
.. index:: random
- :refguide: random;distributions, random;gauss""")
+ :refguide: random;distributions, random;gauss""",
+ )
def test_yield_str():
- line_by_line_compare(str(doc_yields),
-"""Test generator
+ line_by_line_compare(
+ str(doc_yields),
+ """Test generator
Yields
------
@@ -509,12 +513,14 @@ b : int
The number of bananas.
int
The number of unknowns.
-""")
+""",
+ )
def test_receives_str():
- line_by_line_compare(str(doc_sent),
-"""Test generator
+ line_by_line_compare(
+ str(doc_sent),
+ """Test generator
Yields
------
@@ -527,29 +533,44 @@ b : int
The number of bananas.
c : int
The number of oranges.
-""")
+""",
+ )
def test_no_index_in_str():
- assert "index" not in str(NumpyDocString("""Test idx
+ assert "index" not in str(
+ NumpyDocString(
+ """Test idx
- """))
+ """
+ )
+ )
- assert "index" in str(NumpyDocString("""Test idx
+ assert "index" in str(
+ NumpyDocString(
+ """Test idx
.. index :: random
- """))
+ """
+ )
+ )
- assert "index" in str(NumpyDocString("""Test idx
+ assert "index" in str(
+ NumpyDocString(
+ """Test idx
.. index ::
foo
- """))
+ """
+ )
+ )
+
def test_sphinx_str():
sphinx_doc = SphinxDocString(doc_txt)
- line_by_line_compare(str(sphinx_doc),
-"""
+ line_by_line_compare(
+ str(sphinx_doc),
+ """
.. index:: random
single: random;distributions, random;gauss
@@ -668,13 +689,15 @@ standard deviation:
>>> print(list((x[0, 0, :] - mean) < 0.6))
[True, True]
-""")
+""",
+ )
def test_sphinx_yields_str():
sphinx_doc = SphinxDocString(doc_yields_txt)
- line_by_line_compare(str(sphinx_doc),
-"""Test generator
+ line_by_line_compare(
+ str(sphinx_doc),
+ """Test generator
:Yields:
@@ -686,10 +709,12 @@ def test_sphinx_yields_str():
int
The number of unknowns.
-""")
+""",
+ )
-doc2 = NumpyDocString("""
+doc2 = NumpyDocString(
+ """
Returns array of indices of the maximum values of along the given axis.
Parameters
@@ -698,39 +723,43 @@ doc2 = NumpyDocString("""
Array to look in.
axis : {None, integer}
If None, the index is into the flattened array, otherwise along
- the specified axis""")
+ the specified axis"""
+)
def test_parameters_without_extended_description():
- assert len(doc2['Parameters']) == 2
+ assert len(doc2["Parameters"]) == 2
-doc3 = NumpyDocString("""
+doc3 = NumpyDocString(
+ """
my_signature(*params, **kwds)
Return this and that.
- """)
+ """
+)
def test_escape_stars():
- signature = str(doc3).split('\n')[0]
- assert signature == r'my_signature(\*params, \*\*kwds)'
+ signature = str(doc3).split("\n")[0]
+ assert signature == r"my_signature(\*params, \*\*kwds)"
def my_func(a, b, **kwargs):
pass
fdoc = FunctionDoc(func=my_func)
- assert fdoc['Signature'] == ''
+ assert fdoc["Signature"] == ""
doc4 = NumpyDocString(
"""a.conj()
- Return an array with all complex-valued elements conjugated.""")
+ Return an array with all complex-valued elements conjugated."""
+)
def test_empty_extended_summary():
- assert doc4['Extended Summary'] == []
+ assert doc4["Extended Summary"] == []
doc5 = NumpyDocString(
@@ -746,34 +775,37 @@ doc5 = NumpyDocString(
-----
SomeWarning
If needed
- """)
+ """
+)
def test_raises():
- assert len(doc5['Raises']) == 1
- param = doc5['Raises'][0]
- assert param.name == ''
- assert param.type == 'LinAlgException'
- assert param.desc == ['If array is singular.']
+ assert len(doc5["Raises"]) == 1
+ param = doc5["Raises"][0]
+ assert param.name == ""
+ assert param.type == "LinAlgException"
+ assert param.desc == ["If array is singular."]
def test_warns():
- assert len(doc5['Warns']) == 1
- param = doc5['Warns'][0]
- assert param.name == ''
- assert param.type == 'SomeWarning'
- assert param.desc == ['If needed']
+ assert len(doc5["Warns"]) == 1
+ param = doc5["Warns"][0]
+ assert param.name == ""
+ assert param.type == "SomeWarning"
+ assert param.desc == ["If needed"]
+
# see numpydoc/numpydoc #281
# we want to correctly parse "See Also" both in docstrings both like
-#"""foo
+# """foo
# and
-#"""
-#foo
-@pytest.mark.parametrize('prefix', ['', '\n '])
+# """
+# foo
+@pytest.mark.parametrize("prefix", ["", "\n "])
def test_see_also(prefix):
doc6 = NumpyDocString(
- prefix + """z(x,theta)
+ prefix
+ + """z(x,theta)
See Also
--------
@@ -789,51 +821,65 @@ def test_see_also(prefix):
:obj:`~baz.obj_r`
:class:`class_j`: fubar
foobar
- """)
+ """
+ )
- assert len(doc6['See Also']) == 10
- for funcs, desc in doc6['See Also']:
+ assert len(doc6["See Also"]) == 10
+ for funcs, desc in doc6["See Also"]:
for func, role in funcs:
- if func in ('func_a', 'func_b', 'func_c', 'func_f',
- 'func_g', 'func_h', 'func_j', 'func_k', 'baz.obj_q',
- 'func_f1', 'func_g1', 'func_h1', 'func_j1',
- '~baz.obj_r'):
+ if func in (
+ "func_a",
+ "func_b",
+ "func_c",
+ "func_f",
+ "func_g",
+ "func_h",
+ "func_j",
+ "func_k",
+ "baz.obj_q",
+ "func_f1",
+ "func_g1",
+ "func_h1",
+ "func_j1",
+ "~baz.obj_r",
+ ):
assert not desc, str([func, desc])
- elif func in ('func_f2', 'func_g2', 'func_h2', 'func_j2'):
+ elif func in ("func_f2", "func_g2", "func_h2", "func_j2"):
assert desc, str([func, desc])
else:
assert desc, str([func, desc])
- if func == 'func_h':
- assert role == 'meth'
- elif func == 'baz.obj_q' or func == '~baz.obj_r':
- assert role == 'obj'
- elif func == 'class_j':
- assert role == 'class'
- elif func in ['func_h1', 'func_h2']:
- assert role == 'meth'
+ if func == "func_h":
+ assert role == "meth"
+ elif func == "baz.obj_q" or func == "~baz.obj_r":
+ assert role == "obj"
+ elif func == "class_j":
+ assert role == "class"
+ elif func in ["func_h1", "func_h2"]:
+ assert role == "meth"
else:
assert role is None, str([func, role])
- if func == 'func_d':
- assert desc == ['some equivalent func']
- elif func == 'foo.func_e':
- assert desc == ['some other func over', 'multiple lines']
- elif func == 'class_j':
- assert desc == ['fubar', 'foobar']
- elif func in ['func_f2', 'func_g2', 'func_h2', 'func_j2']:
- assert desc == ['description of multiple'], str([desc, ['description of multiple']])
+ if func == "func_d":
+ assert desc == ["some equivalent func"]
+ elif func == "foo.func_e":
+ assert desc == ["some other func over", "multiple lines"]
+ elif func == "class_j":
+ assert desc == ["fubar", "foobar"]
+ elif func in ["func_f2", "func_g2", "func_h2", "func_j2"]:
+ assert desc == ["description of multiple"], str(
+ [desc, ["description of multiple"]]
+ )
def test_see_also_parse_error():
- text = (
- """
+ text = """
z(x,theta)
See Also
--------
:func:`~foo`
- """)
+ """
with pytest.raises(ValueError, match="See Also entry ':func:`~foo`'"):
NumpyDocString(text)
@@ -848,17 +894,21 @@ def test_see_also_print():
goes here
func_d
"""
+
pass
- s = str(FunctionDoc(Dummy, role='func'))
- assert(':func:`func_a`, :func:`func_b`' in s)
- assert(' some relationship' in s)
- assert(':func:`func_d`' in s)
+ s = str(FunctionDoc(Dummy, role="func"))
+ assert ":func:`func_a`, :func:`func_b`" in s
+ assert " some relationship" in s
+ assert ":func:`func_d`" in s
def test_see_also_trailing_comma_warning():
- warnings.filterwarnings('error')
- with assert_warns(Warning, match='Unexpected comma or period after function list at index 43 of line .*'):
+ warnings.filterwarnings("error")
+ with assert_warns(
+ Warning,
+ match="Unexpected comma or period after function list at index 43 of line .*",
+ ):
NumpyDocString(
"""
z(x,theta)
@@ -868,7 +918,8 @@ def test_see_also_trailing_comma_warning():
func_f2, func_g2, :meth:`func_h2`, func_j2, : description of multiple
:class:`class_j`: fubar
foobar
- """)
+ """
+ )
def test_unknown_section():
@@ -887,6 +938,7 @@ This should be ignored and warned about
----
This class has a nope section.
"""
+
pass
with pytest.warns(UserWarning, match="Unknown section Mope") as record:
@@ -901,17 +953,21 @@ This should be ignored and warned about
assert len(record) == 1
-doc7 = NumpyDocString("""
+doc7 = NumpyDocString(
+ """
Doc starts on second line.
- """)
+ """
+)
def test_empty_first_line():
- assert doc7['Summary'][0].startswith('Doc starts')
+ assert doc7["Summary"][0].startswith("Doc starts")
-doc8 = NumpyDocString("""
+
+doc8 = NumpyDocString(
+ """
Parameters with colon and no types:
@@ -920,21 +976,27 @@ doc8 = NumpyDocString("""
data :
some stuff, technically invalid
- """)
+ """
+)
def test_trailing_colon():
- assert doc8['Parameters'][0].name == 'data'
+ assert doc8["Parameters"][0].name == "data"
def test_no_summary():
- str(SphinxDocString("""
+ str(
+ SphinxDocString(
+ """
Parameters
- ----------"""))
+ ----------"""
+ )
+ )
def test_unicode():
- doc = SphinxDocString("""
+ doc = SphinxDocString(
+ """
öäöäöäöäöåååå
öäöäöäööäååå
@@ -949,33 +1011,41 @@ def test_unicode():
ååå : ööö
äää
- """)
- assert isinstance(doc['Summary'][0], str)
- assert doc['Summary'][0] == 'öäöäöäöäöåååå'
+ """
+ )
+ assert isinstance(doc["Summary"][0], str)
+ assert doc["Summary"][0] == "öäöäöäöäöåååå"
def test_plot_examples():
cfg = dict(use_plots=True)
- doc = SphinxDocString("""
+ doc = SphinxDocString(
+ """
Examples
--------
>>> import matplotlib.pyplot as plt
>>> plt.plot([1,2,3],[4,5,6])
>>> plt.show()
- """, config=cfg)
- assert 'plot::' in str(doc), str(doc)
+ """,
+ config=cfg,
+ )
+ assert "plot::" in str(doc), str(doc)
- doc = SphinxDocString("""
+ doc = SphinxDocString(
+ """
Examples
--------
>>> from matplotlib import pyplot as plt
>>> plt.plot([1,2,3],[4,5,6])
>>> plt.show()
- """, config=cfg)
- assert 'plot::' in str(doc), str(doc)
+ """,
+ config=cfg,
+ )
+ assert "plot::" in str(doc), str(doc)
- doc = SphinxDocString("""
+ doc = SphinxDocString(
+ """
Examples
--------
.. plot::
@@ -983,13 +1053,16 @@ def test_plot_examples():
import matplotlib.pyplot as plt
plt.plot([1,2,3],[4,5,6])
plt.show()
- """, config=cfg)
- assert str(doc).count('plot::') == 1, str(doc)
+ """,
+ config=cfg,
+ )
+ assert str(doc).count("plot::") == 1, str(doc)
def test_use_blockquotes():
cfg = dict(use_blockquotes=True)
- doc = SphinxDocString("""
+ doc = SphinxDocString(
+ """
Parameters
----------
abc : def
@@ -1003,8 +1076,12 @@ def test_use_blockquotes():
GHI
JKL
MNO
- """, config=cfg)
- line_by_line_compare(str(doc), '''
+ """,
+ config=cfg,
+ )
+ line_by_line_compare(
+ str(doc),
+ """
:Parameters:
**abc** : def
@@ -1024,22 +1101,25 @@ def test_use_blockquotes():
JKL
MNO
- ''')
+ """,
+ )
def test_class_members():
-
class Dummy:
"""
Dummy class.
"""
+
def spam(self, a, b):
"""Spam\n\nSpam spam."""
pass
+
def ham(self, c, d):
"""Cheese\n\nNo cheese."""
pass
+
@property
def spammity(self):
"""Spammity index"""
@@ -1047,32 +1127,34 @@ def test_class_members():
class Ignorable:
"""local class, to be ignored"""
+
pass
for cls in (ClassDoc, SphinxClassDoc):
doc = cls(Dummy, config=dict(show_class_members=False))
- assert 'Methods' not in str(doc), (cls, str(doc))
- assert 'spam' not in str(doc), (cls, str(doc))
- assert 'ham' not in str(doc), (cls, str(doc))
- assert 'spammity' not in str(doc), (cls, str(doc))
- assert 'Spammity index' not in str(doc), (cls, str(doc))
+ assert "Methods" not in str(doc), (cls, str(doc))
+ assert "spam" not in str(doc), (cls, str(doc))
+ assert "ham" not in str(doc), (cls, str(doc))
+ assert "spammity" not in str(doc), (cls, str(doc))
+ assert "Spammity index" not in str(doc), (cls, str(doc))
doc = cls(Dummy, config=dict(show_class_members=True))
- assert 'Methods' in str(doc), (cls, str(doc))
- assert 'spam' in str(doc), (cls, str(doc))
- assert 'ham' in str(doc), (cls, str(doc))
- assert 'spammity' in str(doc), (cls, str(doc))
+ assert "Methods" in str(doc), (cls, str(doc))
+ assert "spam" in str(doc), (cls, str(doc))
+ assert "ham" in str(doc), (cls, str(doc))
+ assert "spammity" in str(doc), (cls, str(doc))
if cls is SphinxClassDoc:
- assert '.. autosummary::' in str(doc), str(doc)
+ assert ".. autosummary::" in str(doc), str(doc)
else:
- assert 'Spammity index' in str(doc), str(doc)
+ assert "Spammity index" in str(doc), str(doc)
class SubDummy(Dummy):
"""
Subclass of Dummy class.
"""
+
def ham(self, c, d):
"""Cheese\n\nNo cheese.\nOverloaded Dummy.ham"""
pass
@@ -1082,31 +1164,35 @@ def test_class_members():
pass
for cls in (ClassDoc, SphinxClassDoc):
- doc = cls(SubDummy, config=dict(show_class_members=True,
- show_inherited_class_members=False))
- assert 'Methods' in str(doc), (cls, str(doc))
- assert 'spam' not in str(doc), (cls, str(doc))
- assert 'ham' in str(doc), (cls, str(doc))
- assert 'bar' in str(doc), (cls, str(doc))
- assert 'spammity' not in str(doc), (cls, str(doc))
+ doc = cls(
+ SubDummy,
+ config=dict(show_class_members=True, show_inherited_class_members=False),
+ )
+ assert "Methods" in str(doc), (cls, str(doc))
+ assert "spam" not in str(doc), (cls, str(doc))
+ assert "ham" in str(doc), (cls, str(doc))
+ assert "bar" in str(doc), (cls, str(doc))
+ assert "spammity" not in str(doc), (cls, str(doc))
if cls is SphinxClassDoc:
- assert '.. autosummary::' in str(doc), str(doc)
+ assert ".. autosummary::" in str(doc), str(doc)
else:
- assert 'Spammity index' not in str(doc), str(doc)
+ assert "Spammity index" not in str(doc), str(doc)
- doc = cls(SubDummy, config=dict(show_class_members=True,
- show_inherited_class_members=True))
- assert 'Methods' in str(doc), (cls, str(doc))
- assert 'spam' in str(doc), (cls, str(doc))
- assert 'ham' in str(doc), (cls, str(doc))
- assert 'bar' in str(doc), (cls, str(doc))
- assert 'spammity' in str(doc), (cls, str(doc))
+ doc = cls(
+ SubDummy,
+ config=dict(show_class_members=True, show_inherited_class_members=True),
+ )
+ assert "Methods" in str(doc), (cls, str(doc))
+ assert "spam" in str(doc), (cls, str(doc))
+ assert "ham" in str(doc), (cls, str(doc))
+ assert "bar" in str(doc), (cls, str(doc))
+ assert "spammity" in str(doc), (cls, str(doc))
if cls is SphinxClassDoc:
- assert '.. autosummary::' in str(doc), str(doc)
+ assert ".. autosummary::" in str(doc), str(doc)
else:
- assert 'Spammity index' in str(doc), str(doc)
+ assert "Spammity index" in str(doc), str(doc)
def test_duplicate_signature():
@@ -1115,13 +1201,14 @@ def test_duplicate_signature():
# docstring itself.
doc = NumpyDocString(
- """
+ """
z(x1, x2)
z(a, theta)
- """)
+ """
+ )
- assert doc['Signature'].strip() == 'z(a, theta)'
+ assert doc["Signature"].strip() == "z(a, theta)"
class_doc_txt = """
@@ -1167,8 +1254,9 @@ class_doc_txt = """
def test_class_members_doc():
doc = ClassDoc(None, class_doc_txt)
- line_by_line_compare(str(doc),
- """
+ line_by_line_compare(
+ str(doc),
+ """
Foo
Parameters
@@ -1206,7 +1294,8 @@ def test_class_members_doc():
b
c
- """)
+ """,
+ )
def test_class_members_doc_sphinx():
@@ -1245,8 +1334,9 @@ def test_class_members_doc_sphinx():
return None
doc = SphinxClassDoc(Foo, class_doc_txt)
- line_by_line_compare(str(doc),
- """
+ line_by_line_compare(
+ str(doc),
+ """
Foo
:Parameters:
@@ -1298,11 +1388,11 @@ def test_class_members_doc_sphinx():
**c**
===== ==========
- """)
+ """,
+ )
def test_class_attributes_as_member_list():
-
class Foo:
"""
Class docstring.
@@ -1313,6 +1403,7 @@ def test_class_attributes_as_member_list():
Another description that is not used.
"""
+
@property
def an_attribute(self):
"""Test attribute"""
@@ -1339,10 +1430,14 @@ def test_class_attributes_as_member_list():
def test_templated_sections():
- doc = SphinxClassDoc(None, class_doc_txt,
- config={'template': jinja2.Template('{{examples}}\n{{parameters}}')})
- line_by_line_compare(str(doc),
- """
+ doc = SphinxClassDoc(
+ None,
+ class_doc_txt,
+ config={"template": jinja2.Template("{{examples}}\n{{parameters}}")},
+ )
+ line_by_line_compare(
+ str(doc),
+ """
.. rubric:: Examples
For usage examples, see `ode`.
@@ -1355,14 +1450,14 @@ def test_templated_sections():
**jac** : callable ``jac(t, y, *jac_args)``
Bbb.
- """)
+ """,
+ )
def test_nonstandard_property():
# test discovery of a property that does not satisfy isinstace(.., property)
class SpecialProperty:
-
def __init__(self, axis=0, doc=""):
self.axis = axis
self.__doc__ = doc
@@ -1387,7 +1482,8 @@ def test_nonstandard_property():
def test_args_and_kwargs():
cfg = dict()
- doc = SphinxDocString("""
+ doc = SphinxDocString(
+ """
Parameters
----------
param1 : int
@@ -1396,8 +1492,12 @@ def test_args_and_kwargs():
Arguments
**kwargs : dict
Keyword arguments
- """, config=cfg)
- line_by_line_compare(str(doc), r"""
+ """,
+ config=cfg,
+ )
+ line_by_line_compare(
+ str(doc),
+ r"""
:Parameters:
**param1** : int
@@ -1408,17 +1508,24 @@ def test_args_and_kwargs():
**\*\*kwargs** : dict
Keyword arguments
- """)
+ """,
+ )
+
def test_autoclass():
- cfg=dict(show_class_members=True,
- show_inherited_class_members=True)
- doc = SphinxClassDoc(str, '''
+ cfg = dict(show_class_members=True, show_inherited_class_members=True)
+ doc = SphinxClassDoc(
+ str,
+ """
A top section before
.. autoclass:: str
- ''', config=cfg)
- line_by_line_compare(str(doc), r'''
+ """,
+ config=cfg,
+ )
+ line_by_line_compare(
+ str(doc),
+ r"""
A top section before
.. autoclass:: str
@@ -1426,7 +1533,9 @@ A top section before
.. rubric:: Methods
- ''', 5)
+ """,
+ 5,
+ )
xref_doc_txt = """
@@ -1489,10 +1598,10 @@ Test xref in Parameters, Other Parameters and Returns
def test_xref():
xref_aliases = {
- 'sequence': ':obj:`python:sequence`',
+ "sequence": ":obj:`python:sequence`",
}
- class Config():
+ class Config:
def __init__(self, a, b):
self.numpydoc_xref_aliases = a
self.numpydoc_xref_aliases_complete = b
@@ -1504,18 +1613,18 @@ def test_xref():
for key in xref_aliases:
xref_aliases_complete[key] = xref_aliases[key]
config = Config(xref_aliases, xref_aliases_complete)
- app = namedtuple('config', 'config')(config)
+ app = namedtuple("config", "config")(config)
update_config(app)
- xref_ignore = {'of', 'default', 'optional'}
+ xref_ignore = {"of", "default", "optional"}
doc = SphinxDocString(
xref_doc_txt,
config=dict(
xref_param_type=True,
xref_aliases=xref_aliases_complete,
- xref_ignore=xref_ignore
- )
+ xref_ignore=xref_ignore,
+ ),
)
line_by_line_compare(str(doc), xref_doc_txt_expected)
@@ -1531,11 +1640,10 @@ def test__error_location_no_name_attr():
from collections.abc import Callable
# Create a Callable that doesn't have a __name__ attribute
- class Foo():
+ class Foo:
def __call__(self):
pass
-
foo = Foo() # foo is a Callable, but no a function instance
assert isinstance(foo, Callable)
@@ -1549,4 +1657,5 @@ def test__error_location_no_name_attr():
if __name__ == "__main__":
import pytest
+
pytest.main()
diff --git a/numpydoc/tests/test_full.py b/numpydoc/tests/test_full.py
index 16e60e5..e0defe2 100644
--- a/numpydoc/tests/test_full.py
+++ b/numpydoc/tests/test_full.py
@@ -9,27 +9,28 @@ from sphinx.util.docutils import docutils_namespace
# Test framework adapted from sphinx-gallery (BSD 3-clause)
-@pytest.fixture(scope='module')
+@pytest.fixture(scope="module")
def sphinx_app(tmpdir_factory):
- temp_dir = (tmpdir_factory.getbasetemp() / 'root').strpath
- src_dir = op.join(op.dirname(__file__), 'tinybuild')
+ temp_dir = (tmpdir_factory.getbasetemp() / "root").strpath
+ src_dir = op.join(op.dirname(__file__), "tinybuild")
def ignore(src, names):
- return ('_build', 'generated')
+ return ("_build", "generated")
shutil.copytree(src_dir, temp_dir, ignore=ignore)
# For testing iteration, you can get similar behavior just doing `make`
# inside the tinybuild directory
src_dir = temp_dir
conf_dir = temp_dir
- out_dir = op.join(temp_dir, '_build', 'html')
- toctrees_dir = op.join(temp_dir, '_build', 'toctrees')
- kwargs = {'warningiserror': True, 'keep_going': True}
+ out_dir = op.join(temp_dir, "_build", "html")
+ toctrees_dir = op.join(temp_dir, "_build", "toctrees")
+ kwargs = {"warningiserror": True, "keep_going": True}
# Avoid warnings about re-registration, see:
# https://github.com/sphinx-doc/sphinx/issues/5038
with docutils_namespace():
- app = Sphinx(src_dir, conf_dir, out_dir, toctrees_dir,
- buildername='html', **kwargs)
+ app = Sphinx(
+ src_dir, conf_dir, out_dir, toctrees_dir, buildername="html", **kwargs
+ )
# need to build within the context manager
# for automodule and backrefs to work
app.build(False, [])
@@ -39,46 +40,48 @@ def sphinx_app(tmpdir_factory):
def test_MyClass(sphinx_app):
"""Test that class documentation is reasonable."""
src_dir, out_dir = sphinx_app.srcdir, sphinx_app.outdir
- class_rst = op.join(src_dir, 'generated',
- 'numpydoc_test_module.MyClass.rst')
+ class_rst = op.join(src_dir, "generated", "numpydoc_test_module.MyClass.rst")
with open(class_rst) as fid:
rst = fid.read()
- assert r'numpydoc\_test\_module' in rst # properly escaped
- class_html = op.join(out_dir, 'generated',
- 'numpydoc_test_module.MyClass.html')
+ assert r"numpydoc\_test\_module" in rst # properly escaped
+ class_html = op.join(out_dir, "generated", "numpydoc_test_module.MyClass.html")
with open(class_html) as fid:
html = fid.read()
# ensure that no autodoc weirdness ($) occurs
- assert '$self' not in html
- assert '/,' not in html
- assert '__init__' in html # inherited
+ assert "$self" not in html
+ assert "/," not in html
+ assert "__init__" in html # inherited
# escaped * chars should no longer be preceded by \'s,
# if we see a \* in the output we know it's incorrect:
- assert r'\*' not in html
+ assert r"\*" not in html
# "self" should not be in the parameter list for the class:
- assert 'self,' not in html
+ assert "self," not in html
# check xref was embedded properly (dict should link using xref):
- assert 'stdtypes.html#dict' in html
+ assert "stdtypes.html#dict" in html
def test_my_function(sphinx_app):
"""Test that function documentation is reasonable."""
out_dir = sphinx_app.outdir
- function_html = op.join(out_dir, 'generated',
- 'numpydoc_test_module.my_function.html')
+ function_html = op.join(
+ out_dir, "generated", "numpydoc_test_module.my_function.html"
+ )
with open(function_html) as fid:
html = fid.read()
- assert r'\*args' not in html
- assert '*args' in html
+ assert r"\*args" not in html
+ assert "*args" in html
# check xref (iterable should link using xref):
- assert 'glossary.html#term-iterable' in html
+ assert "glossary.html#term-iterable" in html
-@pytest.mark.parametrize(("html_file", "expected_length"), (
- (["index.html"], 1),
- (["generated", "numpydoc_test_module.my_function.html"], 1),
- (["generated", "numpydoc_test_module.MyClass.html"], 1),
-))
+@pytest.mark.parametrize(
+ ("html_file", "expected_length"),
+ (
+ (["index.html"], 1),
+ (["generated", "numpydoc_test_module.my_function.html"], 1),
+ (["generated", "numpydoc_test_module.MyClass.html"], 1),
+ ),
+)
def test_reference(sphinx_app, html_file, expected_length):
"""Test for bad references"""
out_dir = sphinx_app.outdir
@@ -90,4 +93,4 @@ def test_reference(sphinx_app, html_file, expected_length):
assert len(reference_list) == expected_length
for ref in reference_list:
- assert '-' not in ref # Bad reference if it contains "-" e.g. R1896e33633d5-1
+ assert "-" not in ref # Bad reference if it contains "-" e.g. R1896e33633d5-1
diff --git a/numpydoc/tests/test_main.py b/numpydoc/tests/test_main.py
index 1ba2549..1f90b96 100644
--- a/numpydoc/tests/test_main.py
+++ b/numpydoc/tests/test_main.py
@@ -37,7 +37,7 @@ def _capture_stdout(func_name, *args, **kwargs):
sys.stdout, old_stdout = f, sys.stdout
try:
func_name(*args, **kwargs)
- return f.getvalue().strip('\n\r')
+ return f.getvalue().strip("\n\r")
finally:
sys.stdout = old_stdout
@@ -65,49 +65,53 @@ def _invalid_docstring():
def test_renders_package_docstring():
- out = _capture_stdout(numpydoc.__main__.render_object,
- 'numpydoc')
- assert out.startswith('This package provides the numpydoc Sphinx')
+ out = _capture_stdout(numpydoc.__main__.render_object, "numpydoc")
+ assert out.startswith("This package provides the numpydoc Sphinx")
def test_renders_module_docstring():
- out = _capture_stdout(numpydoc.__main__.render_object,
- 'numpydoc.__main__')
- assert out.startswith('Implementing `python -m numpydoc` functionality.')
+ out = _capture_stdout(numpydoc.__main__.render_object, "numpydoc.__main__")
+ assert out.startswith("Implementing `python -m numpydoc` functionality.")
def test_renders_function_docstring():
- out = _capture_stdout(numpydoc.__main__.render_object,
- 'numpydoc.tests.test_main._capture_stdout')
- assert out.startswith('Return stdout of calling')
+ out = _capture_stdout(
+ numpydoc.__main__.render_object, "numpydoc.tests.test_main._capture_stdout"
+ )
+ assert out.startswith("Return stdout of calling")
def test_render_object_returns_correct_exit_status():
exit_status = numpydoc.__main__.render_object(
- 'numpydoc.tests.test_main._capture_stdout')
+ "numpydoc.tests.test_main._capture_stdout"
+ )
assert exit_status == 0
with pytest.raises(ValueError):
- numpydoc.__main__.render_object(
- 'numpydoc.tests.test_main._invalid_docstring')
+ numpydoc.__main__.render_object("numpydoc.tests.test_main._invalid_docstring")
def test_validate_detects_errors():
- out = _capture_stdout(numpydoc.__main__.validate_object,
- 'numpydoc.tests.test_main._docstring_with_errors')
- assert 'SS02' in out
- assert 'Summary does not start with a capital letter' in out
+ out = _capture_stdout(
+ numpydoc.__main__.validate_object,
+ "numpydoc.tests.test_main._docstring_with_errors",
+ )
+ assert "SS02" in out
+ assert "Summary does not start with a capital letter" in out
exit_status = numpydoc.__main__.validate_object(
- 'numpydoc.tests.test_main._docstring_with_errors')
+ "numpydoc.tests.test_main._docstring_with_errors"
+ )
assert exit_status > 0
def test_validate_perfect_docstring():
- out = _capture_stdout(numpydoc.__main__.validate_object,
- 'numpydoc.tests.test_main._capture_stdout')
- assert out == ''
+ out = _capture_stdout(
+ numpydoc.__main__.validate_object, "numpydoc.tests.test_main._capture_stdout"
+ )
+ assert out == ""
exit_status = numpydoc.__main__.validate_object(
- 'numpydoc.tests.test_main._capture_stdout')
+ "numpydoc.tests.test_main._capture_stdout"
+ )
assert exit_status == 0
diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py
index 5888d9e..0c8b6d6 100644
--- a/numpydoc/tests/test_numpydoc.py
+++ b/numpydoc/tests/test_numpydoc.py
@@ -1,15 +1,13 @@
import pytest
from io import StringIO
from copy import deepcopy
-from numpydoc.numpydoc import (
- mangle_docstrings, _clean_text_signature, update_config
-)
+from numpydoc.numpydoc import mangle_docstrings, _clean_text_signature, update_config
from numpydoc.xref import DEFAULT_LINKS
from sphinx.ext.autodoc import ALL
from sphinx.util import logging
-class MockConfig():
+class MockConfig:
numpydoc_use_plots = False
numpydoc_use_blockquotes = True
numpydoc_show_class_members = True
@@ -20,17 +18,17 @@ class MockConfig():
numpydoc_xref_aliases_complete = deepcopy(DEFAULT_LINKS)
numpydoc_xref_ignore = set()
templates_path = []
- numpydoc_citation_re = '[a-z0-9_.-]+'
+ numpydoc_citation_re = "[a-z0-9_.-]+"
numpydoc_attributes_as_param_list = True
numpydoc_validation_checks = set()
numpydoc_validation_exclude = set()
-class MockBuilder():
+class MockBuilder:
config = MockConfig()
-class MockApp():
+class MockApp:
config = MockConfig()
builder = MockBuilder()
translator = None
@@ -44,60 +42,65 @@ class MockApp():
def test_mangle_docstrings():
- s = '''
+ s = """
A top section before
.. autoclass:: str
- '''
- lines = s.split('\n')
- mangle_docstrings(MockApp(), 'class', 'str', str, {}, lines)
- assert 'rpartition' in [x.strip() for x in lines]
-
- lines = s.split('\n')
- mangle_docstrings(
- MockApp(), 'class', 'str', str, {'members': ['upper']}, lines)
- assert 'rpartition' not in [x.strip() for x in lines]
- assert 'upper' in [x.strip() for x in lines]
-
- lines = s.split('\n')
+ """
+ lines = s.split("\n")
+ mangle_docstrings(MockApp(), "class", "str", str, {}, lines)
+ assert "rpartition" in [x.strip() for x in lines]
+
+ lines = s.split("\n")
+ mangle_docstrings(MockApp(), "class", "str", str, {"members": ["upper"]}, lines)
+ assert "rpartition" not in [x.strip() for x in lines]
+ assert "upper" in [x.strip() for x in lines]
+
+ lines = s.split("\n")
+ mangle_docstrings(MockApp(), "class", "str", str, {"exclude-members": ALL}, lines)
+ assert "rpartition" not in [x.strip() for x in lines]
+ assert "upper" not in [x.strip() for x in lines]
+
+ lines = s.split("\n")
mangle_docstrings(
- MockApp(), 'class', 'str', str, {'exclude-members': ALL}, lines)
- assert 'rpartition' not in [x.strip() for x in lines]
- assert 'upper' not in [x.strip() for x in lines]
-
- lines = s.split('\n')
- mangle_docstrings(
- MockApp(), 'class', 'str', str, {'exclude-members': ['upper']}, lines)
- assert 'rpartition' in [x.strip() for x in lines]
- assert 'upper' not in [x.strip() for x in lines]
+ MockApp(), "class", "str", str, {"exclude-members": ["upper"]}, lines
+ )
+ assert "rpartition" in [x.strip() for x in lines]
+ assert "upper" not in [x.strip() for x in lines]
def test_clean_text_signature():
assert _clean_text_signature(None) is None
- assert _clean_text_signature('func($self)') == 'func()'
- assert (_clean_text_signature('func($self, *args, **kwargs)')
- == 'func(*args, **kwargs)')
- assert _clean_text_signature('($self)') == '()'
- assert _clean_text_signature('()') == '()'
- assert _clean_text_signature('func()') == 'func()'
- assert (_clean_text_signature('func($self, /, *args, **kwargs)')
- == 'func(*args, **kwargs)')
- assert (_clean_text_signature('func($self, other, /, *args, **kwargs)')
- == 'func(other, *args, **kwargs)')
- assert _clean_text_signature('($module)') == '()'
- assert _clean_text_signature('func($type)') == 'func()'
- assert (_clean_text_signature('func($self, foo="hello world")')
- == 'func(foo="hello world")')
- assert (_clean_text_signature("func($self, foo='hello world')")
- == "func(foo='hello world')")
- assert (_clean_text_signature('func(foo="hello world")')
- == 'func(foo="hello world")')
- assert (_clean_text_signature('func(foo="$self")')
- == 'func(foo="$self")')
- assert (_clean_text_signature('func($self, foo="$self")')
- == 'func(foo="$self")')
- assert _clean_text_signature('func(self, other)') == 'func(self, other)'
- assert _clean_text_signature('func($self, *args)') == 'func(*args)'
+ assert _clean_text_signature("func($self)") == "func()"
+ assert (
+ _clean_text_signature("func($self, *args, **kwargs)") == "func(*args, **kwargs)"
+ )
+ assert _clean_text_signature("($self)") == "()"
+ assert _clean_text_signature("()") == "()"
+ assert _clean_text_signature("func()") == "func()"
+ assert (
+ _clean_text_signature("func($self, /, *args, **kwargs)")
+ == "func(*args, **kwargs)"
+ )
+ assert (
+ _clean_text_signature("func($self, other, /, *args, **kwargs)")
+ == "func(other, *args, **kwargs)"
+ )
+ assert _clean_text_signature("($module)") == "()"
+ assert _clean_text_signature("func($type)") == "func()"
+ assert (
+ _clean_text_signature('func($self, foo="hello world")')
+ == 'func(foo="hello world")'
+ )
+ assert (
+ _clean_text_signature("func($self, foo='hello world')")
+ == "func(foo='hello world')"
+ )
+ assert _clean_text_signature('func(foo="hello world")') == 'func(foo="hello world")'
+ assert _clean_text_signature('func(foo="$self")') == 'func(foo="$self")'
+ assert _clean_text_signature('func($self, foo="$self")') == 'func(foo="$self")'
+ assert _clean_text_signature("func(self, other)") == "func(self, other)"
+ assert _clean_text_signature("func($self, *args)") == "func(*args)"
@pytest.fixture
@@ -109,22 +112,23 @@ def f():
Expect SA01 and EX01 errors if validation enabled.
"""
pass
+
return _function_without_seealso_and_examples
@pytest.mark.parametrize(
(
- 'numpydoc_validation_checks',
- 'expected_warn',
- 'non_warnings',
+ "numpydoc_validation_checks",
+ "expected_warn",
+ "non_warnings",
),
(
# Validation configured off - expect no warnings
(set(), [], []),
# Validation on with expected warnings
- ({'SA01', 'EX01'}, ('SA01', 'EX01'), []),
+ ({"SA01", "EX01"}, ("SA01", "EX01"), []),
# Validation on with only one activated check
- ({'SA01'}, ('SA01',), ('EX01',)),
+ ({"SA01"}, ("SA01",), ("EX01",)),
),
)
def test_mangle_docstring_validation_warnings(
@@ -142,7 +146,7 @@ def test_mangle_docstring_validation_warnings(
status, warning = StringIO(), StringIO()
logging.setup(app, status, warning)
# Run mangle docstrings with the above configuration
- mangle_docstrings(app, 'function', 'f', f, None, f.__doc__.split('\n'))
+ mangle_docstrings(app, "function", "f", f, None, f.__doc__.split("\n"))
# Assert that all (and only) expected warnings are logged
warnings = warning.getvalue()
for w in expected_warn:
@@ -155,6 +159,7 @@ def test_mangle_docstring_validation_exclude():
def function_with_bad_docstring():
"""
This docstring will raise docstring validation warnings."""
+
app = MockApp()
app.config.numpydoc_validation_checks = {"all"}
app.config.numpydoc_validation_exclude = [r"_bad_"]
@@ -166,11 +171,11 @@ def test_mangle_docstring_validation_exclude():
# Run mangle docstrings on function_with_bad_docstring
mangle_docstrings(
app,
- 'function',
+ "function",
function_with_bad_docstring.__name__,
function_with_bad_docstring,
None,
- function_with_bad_docstring.__doc__.split('\n'),
+ function_with_bad_docstring.__doc__.split("\n"),
)
# Validation is skipped due to exclude pattern matching fn name, therefore
# no warnings expected
@@ -195,4 +200,5 @@ def test_update_config_exclude_str():
if __name__ == "__main__":
import pytest
+
pytest.main()
diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py
index 3f2d442..97c621e 100644
--- a/numpydoc/tests/test_validate.py
+++ b/numpydoc/tests/test_validate.py
@@ -22,6 +22,7 @@ class GoodDocStrings:
--------
>>> result = 1 + 1
"""
+
def one_liner(self):
"""Allow one liner docstrings (including quotes)."""
# This should fail, but not because of the position of the quotes
@@ -248,7 +249,7 @@ class GoodDocStrings:
"""
return 1
- def contains(self, pat, case=True, na=float('NaN')):
+ def contains(self, pat, case=True, na=float("NaN")):
"""
Return whether each value contains `pat`.
@@ -483,8 +484,7 @@ class GoodDocStrings:
class BadGenericDocStrings:
- """Everything here has a bad docstring
- """
+ """Everything here has a bad docstring"""
def func(self):
@@ -656,6 +656,7 @@ class BadGenericDocStrings:
"""
pass
+
class WarnGenericFormat:
"""
Those contains things that _may_ be incorrect formatting.
@@ -735,6 +736,7 @@ class BadParameters:
"""
Everything here has a problem with its Parameters section.
"""
+
def no_type(self, value):
"""
Lacks the type.
@@ -1083,10 +1085,15 @@ class TestValidator:
return base_path
def test_one_liner(self, capsys):
- result = validate_one(self._import_path(klass="GoodDocStrings", func='one_liner'))
+ result = validate_one(
+ self._import_path(klass="GoodDocStrings", func="one_liner")
+ )
errors = " ".join(err[1] for err in result["errors"])
- assert 'should start in the line immediately after the opening quotes' not in errors
- assert 'should be placed in the line after the last text' not in errors
+ assert (
+ "should start in the line immediately after the opening quotes"
+ not in errors
+ )
+ assert "should be placed in the line after the last text" not in errors
def test_good_class(self, capsys):
errors = validate_one(self._import_path(klass="GoodDocStrings"))["errors"]
@@ -1137,9 +1144,8 @@ class TestValidator:
with pytest.warns(UserWarning):
errors = validate_one(
self._import_path(klass="WarnGenericFormat", func=func) # noqa:F821
- )
- assert 'is too short' in w.msg
-
+ )
+ assert "is too short" in w.msg
@pytest.mark.parametrize(
"func",
@@ -1219,8 +1225,10 @@ class TestValidator:
(
"BadSummaries",
"wrong_line",
- ("should start in the line immediately after the opening quotes",
- "should be placed in the line after the last text"),
+ (
+ "should start in the line immediately after the opening quotes",
+ "should be placed in the line after the last text",
+ ),
),
("BadSummaries", "no_punctuation", ("Summary does not end with a period",)),
(
@@ -1381,7 +1389,7 @@ class TestValidator:
with warnings.catch_warnings(record=True) as w:
result = validate_one(self._import_path(klass=klass, func=func))
if len(w):
- assert all('Unknown section' in str(ww.message) for ww in w)
+ assert all("Unknown section" in str(ww.message) for ww in w)
for msg in msgs:
assert msg in " ".join(err[1] for err in result["errors"])
diff --git a/numpydoc/tests/test_xref.py b/numpydoc/tests/test_xref.py
index 175cb98..b4b3125 100644
--- a/numpydoc/tests/test_xref.py
+++ b/numpydoc/tests/test_xref.py
@@ -196,23 +196,25 @@ dict[tuple(str, str), int]
:class:`python:dict`\[:class:`python:tuple`\(:class:`python:str`, :class:`python:str`), :class:`python:int`]
""" # noqa: E501
-xref_ignore = {'or', 'in', 'of', 'default', 'optional'}
+xref_ignore = {"or", "in", "of", "default", "optional"}
@pytest.mark.parametrize(
- ('param_type', 'expected_result'),
- [tuple(s.split('\n')) for s in data.strip().split('\n\n')]
+ ("param_type", "expected_result"),
+ [tuple(s.split("\n")) for s in data.strip().split("\n\n")],
)
def test_make_xref(param_type, expected_result):
assert make_xref(param_type, xref_aliases, xref_ignore) == expected_result
+
@pytest.mark.parametrize(
- ('param_type', 'expected_result'),
- [tuple(s.split('\n')) for s in data_ignore_obj.strip().split('\n\n')]
+ ("param_type", "expected_result"),
+ [tuple(s.split("\n")) for s in data_ignore_obj.strip().split("\n\n")],
)
def test_make_xref_ignore_unknown(param_type, expected_result):
assert make_xref(param_type, xref_aliases, xref_ignore="all") == expected_result
+
def test_xref_ignore_is_all():
with pytest.raises(TypeError, match="must be a set or 'all'"):
make_xref("array_like", xref_aliases, xref_ignore="foo")
diff --git a/numpydoc/tests/tinybuild/conf.py b/numpydoc/tests/tinybuild/conf.py
index a31380a..fb3b528 100644
--- a/numpydoc/tests/tinybuild/conf.py
+++ b/numpydoc/tests/tinybuild/conf.py
@@ -1,24 +1,26 @@
import os
import sys
+
path = os.path.dirname(__file__)
if path not in sys.path:
sys.path.insert(0, path)
import numpydoc_test_module # noqa
+
extensions = [
- 'sphinx.ext.autodoc',
- 'sphinx.ext.intersphinx',
- 'numpydoc',
+ "sphinx.ext.autodoc",
+ "sphinx.ext.intersphinx",
+ "numpydoc",
]
-project = 'numpydoc_test_module'
+project = "numpydoc_test_module"
autosummary_generate = True
-autodoc_default_options = {'inherited-members': None}
-source_suffix = '.rst'
-master_doc = 'index' # NOTE: will be changed to `root_doc` in sphinx 4
-exclude_patterns = ['_build']
+autodoc_default_options = {"inherited-members": None}
+source_suffix = ".rst"
+master_doc = "index" # NOTE: will be changed to `root_doc` in sphinx 4
+exclude_patterns = ["_build"]
intersphinx_mapping = {
- 'python': ('https://docs.python.org/3', None),
+ "python": ("https://docs.python.org/3", None),
}
nitpicky = True
-highlight_language = 'python3'
+highlight_language = "python3"
numpydoc_class_members_toctree = False
numpydoc_xref_param_type = True
diff --git a/numpydoc/tests/tinybuild/numpydoc_test_module.py b/numpydoc/tests/tinybuild/numpydoc_test_module.py
index bf55979..d303e9e 100644
--- a/numpydoc/tests/tinybuild/numpydoc_test_module.py
+++ b/numpydoc/tests/tinybuild/numpydoc_test_module.py
@@ -15,7 +15,7 @@ References
.. [1] https://numpydoc.readthedocs.io
"""
-__all__ = ['MyClass', 'my_function']
+__all__ = ["MyClass", "my_function"]
class MyClass:
diff --git a/numpydoc/validate.py b/numpydoc/validate.py
index d1ee978..780d895 100644
--- a/numpydoc/validate.py
+++ b/numpydoc/validate.py
@@ -16,8 +16,9 @@ from .docscrape import get_doc_object
DIRECTIVES = ["versionadded", "versionchanged", "deprecated"]
-DIRECTIVE_PATTERN = re.compile(r"^\s*\.\. ({})(?!::)".format('|'.join(DIRECTIVES)),
- re.I | re.M)
+DIRECTIVE_PATTERN = re.compile(
+ r"^\s*\.\. ({})(?!::)".format("|".join(DIRECTIVES)), re.I | re.M
+)
ALLOWED_SECTIONS = [
"Parameters",
"Attributes",
@@ -35,58 +36,58 @@ ALLOWED_SECTIONS = [
]
ERROR_MSGS = {
"GL01": "Docstring text (summary) should start in the line immediately "
- "after the opening quotes (not in the same line, or leaving a "
- "blank line in between)",
+ "after the opening quotes (not in the same line, or leaving a "
+ "blank line in between)",
"GL02": "Closing quotes should be placed in the line after the last text "
- "in the docstring (do not close the quotes in the same line as "
- "the text, or leave a blank line between the last text and the "
- "quotes)",
+ "in the docstring (do not close the quotes in the same line as "
+ "the text, or leave a blank line between the last text and the "
+ "quotes)",
"GL03": "Double line break found; please use only one blank line to "
- "separate sections or paragraphs, and do not leave blank lines "
- "at the end of docstrings",
+ "separate sections or paragraphs, and do not leave blank lines "
+ "at the end of docstrings",
"GL05": 'Tabs found at the start of line "{line_with_tabs}", please use '
- "whitespace only",
+ "whitespace only",
"GL06": 'Found unknown section "{section}". Allowed sections are: '
- "{allowed_sections}",
+ "{allowed_sections}",
"GL07": "Sections are in the wrong order. Correct order is: {correct_sections}",
"GL08": "The object does not have a docstring",
"GL09": "Deprecation warning should precede extended summary",
"GL10": "reST directives {directives} must be followed by two colons",
"SS01": "No summary found (a short summary in a single line should be "
- "present at the beginning of the docstring)",
+ "present at the beginning of the docstring)",
"SS02": "Summary does not start with a capital letter",
"SS03": "Summary does not end with a period",
"SS04": "Summary contains heading whitespaces",
"SS05": "Summary must start with infinitive verb, not third person "
- '(e.g. use "Generate" instead of "Generates")',
+ '(e.g. use "Generate" instead of "Generates")',
"SS06": "Summary should fit in a single line",
"ES01": "No extended summary found",
"PR01": "Parameters {missing_params} not documented",
"PR02": "Unknown parameters {unknown_params}",
"PR03": "Wrong parameters order. Actual: {actual_params}. "
- "Documented: {documented_params}",
+ "Documented: {documented_params}",
"PR04": 'Parameter "{param_name}" has no type',
"PR05": 'Parameter "{param_name}" type should not finish with "."',
"PR06": 'Parameter "{param_name}" type should use "{right_type}" instead '
- 'of "{wrong_type}"',
+ 'of "{wrong_type}"',
"PR07": 'Parameter "{param_name}" has no description',
"PR08": 'Parameter "{param_name}" description should start with a '
- "capital letter",
+ "capital letter",
"PR09": 'Parameter "{param_name}" description should finish with "."',
"PR10": 'Parameter "{param_name}" requires a space before the colon '
- "separating the parameter name and type",
+ "separating the parameter name and type",
"RT01": "No Returns section found",
"RT02": "The first line of the Returns section should contain only the "
- "type, unless multiple values are being returned",
+ "type, unless multiple values are being returned",
"RT03": "Return value has no description",
"RT04": "Return value description should start with a capital letter",
"RT05": 'Return value description should finish with "."',
"YD01": "No Yields section found",
"SA01": "See Also section not found",
"SA02": "Missing period at end of description for See Also "
- '"{reference_name}" reference',
+ '"{reference_name}" reference',
"SA03": "Description should be capitalized for See Also "
- '"{reference_name}" reference',
+ '"{reference_name}" reference',
"SA04": 'Missing description for See Also "{reference_name}" reference',
"EX01": "No examples section found",
}
@@ -133,7 +134,7 @@ class Validator:
@property
def name(self):
- return '.'.join([self.obj.__module__, self.obj.__name__])
+ return ".".join([self.obj.__module__, self.obj.__name__])
@staticmethod
def _load_obj(name):
@@ -164,7 +165,7 @@ class Validator:
else:
break
else:
- raise ImportError(f"No module can be imported from \"{name}\"")
+ raise ImportError(f'No module can be imported from "{name}"')
for part in func_parts:
obj = getattr(obj, part)
@@ -438,8 +439,7 @@ def _check_desc(desc, code_no_desc, code_no_upper, code_no_period, **kwargs):
errs.append(error(code_no_upper, **kwargs))
# Not ending in "." is only an error if the last bit is not
# indented (e.g., quote or code block)
- if not desc[-1].endswith(".") and \
- not desc[-1].startswith(IGNORE_STARTS):
+ if not desc[-1].endswith(".") and not desc[-1].startswith(IGNORE_STARTS):
errs.append(error(code_no_period, **kwargs))
return errs
@@ -587,8 +587,7 @@ def validate(obj_name):
wrong_type=wrong_type,
)
)
- errs.extend(_check_desc(
- kind_desc[1], "PR07", "PR08", "PR09", param_name=param))
+ errs.extend(_check_desc(kind_desc[1], "PR07", "PR08", "PR09", param_name=param))
if doc.is_function_or_method:
if not doc.returns:
diff --git a/numpydoc/xref.py b/numpydoc/xref.py
index e3f507d..a0cc8a5 100644
--- a/numpydoc/xref.py
+++ b/numpydoc/xref.py
@@ -16,81 +16,81 @@ import re
QUALIFIED_NAME_RE = re.compile(
# e.g int, numpy.array, ~numpy.array, .class_in_current_module
- r'^'
- r'[~\.]?'
- r'[a-zA-Z_]\w*'
- r'(?:\.[a-zA-Z_]\w*)*'
- r'$'
+ r"^"
+ r"[~\.]?"
+ r"[a-zA-Z_]\w*"
+ r"(?:\.[a-zA-Z_]\w*)*"
+ r"$"
)
CONTAINER_SPLIT_RE = re.compile(
# splits dict(str, int) into
# ['dict', '[', 'str', ', ', 'int', ']', '']
- r'(\s*[\[\]\(\)\{\}]\s*|,\s+)'
+ r"(\s*[\[\]\(\)\{\}]\s*|,\s+)"
)
CONTAINER_SPLIT_REJECT_RE = re.compile(
# Leads to bad markup e.g.
# {int}qualified_name
- r'[\]\)\}]\w'
+ r"[\]\)\}]\w"
)
DOUBLE_QUOTE_SPLIT_RE = re.compile(
# splits 'callable ``f(x0, *args)`` or ``f(x0, y0, *args)``' into
# ['callable ', '``f(x0, *args)``', ' or ', '``f(x0, y0, *args)``', '']
- r'(``.+?``)'
+ r"(``.+?``)"
)
ROLE_SPLIT_RE = re.compile(
# splits to preserve ReST roles
- r'(:\w+:`.+?(?<!\\)`)'
+ r"(:\w+:`.+?(?<!\\)`)"
)
SINGLE_QUOTE_SPLIT_RE = re.compile(
# splits to preserve quoted expressions roles
- r'(`.+?`)'
+ r"(`.+?`)"
)
TEXT_SPLIT_RE = re.compile(
# splits on ' or ', ' | ', ', ' and ' '
- r'(\s+or\s+|\s+\|\s+|,\s+|\s+)'
+ r"(\s+or\s+|\s+\|\s+|,\s+|\s+)"
)
-CONTAINER_CHARS = set('[](){}')
+CONTAINER_CHARS = set("[](){}")
# Save people some time and add some common standard aliases
DEFAULT_LINKS = {
# Python
- 'None': ':data:`python:None`',
- 'bool': ':ref:`bool <python:bltin-boolean-values>`',
- 'boolean': ':ref:`bool <python:bltin-boolean-values>`',
- 'True': ':data:`python:True`',
- 'False': ':data:`python:False`',
- 'list': ':class:`python:list`',
- 'tuple': ':class:`python:tuple`',
- 'str': ':class:`python:str`',
- 'string': ':class:`python:str`',
- 'dict': ':class:`python:dict`',
- 'float': ':class:`python:float`',
- 'int': ':class:`python:int`',
- 'callable': ':func:`python:callable`',
- 'iterable': ':term:`python:iterable`',
- 'sequence': ':term:`python:sequence`',
- 'contextmanager': ':func:`python:contextlib.contextmanager`',
- 'namedtuple': ':func:`python:collections.namedtuple`',
- 'generator': ':term:`python:generator`',
+ "None": ":data:`python:None`",
+ "bool": ":ref:`bool <python:bltin-boolean-values>`",
+ "boolean": ":ref:`bool <python:bltin-boolean-values>`",
+ "True": ":data:`python:True`",
+ "False": ":data:`python:False`",
+ "list": ":class:`python:list`",
+ "tuple": ":class:`python:tuple`",
+ "str": ":class:`python:str`",
+ "string": ":class:`python:str`",
+ "dict": ":class:`python:dict`",
+ "float": ":class:`python:float`",
+ "int": ":class:`python:int`",
+ "callable": ":func:`python:callable`",
+ "iterable": ":term:`python:iterable`",
+ "sequence": ":term:`python:sequence`",
+ "contextmanager": ":func:`python:contextlib.contextmanager`",
+ "namedtuple": ":func:`python:collections.namedtuple`",
+ "generator": ":term:`python:generator`",
# NumPy
- 'array': 'numpy.ndarray',
- 'ndarray': 'numpy.ndarray',
- 'np.ndarray': 'numpy.ndarray',
- 'array-like': ':term:`numpy:array_like`',
- 'array_like': ':term:`numpy:array_like`',
- 'scalar': ':ref:`scalar <numpy:arrays.scalars>`',
- 'RandomState': 'numpy.random.RandomState',
- 'np.random.RandomState': 'numpy.random.RandomState',
- 'np.inf': ':data:`numpy.inf`',
- 'np.nan': ':data:`numpy.nan`',
- 'numpy': ':mod:`numpy`',
+ "array": "numpy.ndarray",
+ "ndarray": "numpy.ndarray",
+ "np.ndarray": "numpy.ndarray",
+ "array-like": ":term:`numpy:array_like`",
+ "array_like": ":term:`numpy:array_like`",
+ "scalar": ":ref:`scalar <numpy:arrays.scalars>`",
+ "RandomState": "numpy.random.RandomState",
+ "np.random.RandomState": "numpy.random.RandomState",
+ "np.inf": ":data:`numpy.inf`",
+ "np.nan": ":data:`numpy.nan`",
+ "numpy": ":mod:`numpy`",
}
@@ -125,9 +125,7 @@ def make_xref(param_type, xref_aliases, xref_ignore):
wrap_unknown = False
ignore_set = set()
else:
- raise TypeError(
- f"xref_ignore must be a set or 'all', got {xref_ignore}"
- )
+ raise TypeError(f"xref_ignore must be a set or 'all', got {xref_ignore}")
if param_type in xref_aliases:
link, title = xref_aliases[param_type], param_type
@@ -137,9 +135,9 @@ def make_xref(param_type, xref_aliases, xref_ignore):
if QUALIFIED_NAME_RE.match(link) and link not in ignore_set:
if link != title:
- return f':obj:`{title} <{link}>`'
+ return f":obj:`{title} <{link}>`"
if wrap_unknown:
- return f':obj:`{link}`'
+ return f":obj:`{link}`"
return link
def _split_and_apply_re(s, pattern):
@@ -160,13 +158,13 @@ def make_xref(param_type, xref_aliases, xref_ignore):
# Opening brackets immediately after a role is
# bad markup. Detect that and add backslash.
# :role:`type`( to :role:`type`\(
- if res and res[-1] == '`' and i < n-1:
- next_char = tokens[i+1][0]
- if next_char in '([{':
- res += '\\'
+ if res and res[-1] == "`" and i < n - 1:
+ next_char = tokens[i + 1][0]
+ if next_char in "([{":
+ res += "\\"
results.append(res)
- return ''.join(results)
+ return "".join(results)
return s
# The cases are dealt with in an order the prevents
@@ -178,15 +176,15 @@ def make_xref(param_type, xref_aliases, xref_ignore):
# - join the results with the pattern
# Unsplittable literal
- if '``' in param_type:
+ if "``" in param_type:
return _split_and_apply_re(param_type, DOUBLE_QUOTE_SPLIT_RE)
# Any roles
- if ':`' in param_type:
+ if ":`" in param_type:
return _split_and_apply_re(param_type, ROLE_SPLIT_RE)
# Any quoted expressions
- if '`' in param_type:
+ if "`" in param_type:
return _split_and_apply_re(param_type, SINGLE_QUOTE_SPLIT_RE)
# Any sort of bracket '[](){}'
diff --git a/setup.py b/setup.py
index 515f849..2683fd9 100644
--- a/setup.py
+++ b/setup.py
@@ -5,13 +5,13 @@ from setuptools import setup
# Adapted from MNE-Python (BSD)
version = None
-with open(os.path.join('numpydoc', '_version.py')) as fid:
+with open(os.path.join("numpydoc", "_version.py")) as fid:
for line in (line.strip() for line in fid):
- if line.startswith('__version__'):
- version = line.split('=')[1].strip().strip('\'')
+ if line.startswith("__version__"):
+ version = line.split("=")[1].strip().strip("'")
break
if version is None:
- raise RuntimeError('Could not determine version')
+ raise RuntimeError("Could not determine version")
if sys.version_info < (3, 7):
raise RuntimeError("Python version >= 3.7 required.")
@@ -33,37 +33,41 @@ setup(
packages=["numpydoc"],
version=version,
description="Sphinx extension to support docstrings in Numpy format",
- long_description=read('README.rst'),
+ long_description=read("README.rst"),
# classifiers from http://pypi.python.org/pypi?%3Aaction=list_classifiers
- classifiers=["Development Status :: 4 - Beta",
- "Environment :: Plugins",
- "License :: OSI Approved :: BSD License",
- "Topic :: Documentation",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- ],
+ classifiers=[
+ "Development Status :: 4 - Beta",
+ "Environment :: Plugins",
+ "License :: OSI Approved :: BSD License",
+ "Topic :: Documentation",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ ],
keywords="sphinx numpy",
author="Pauli Virtanen and others",
author_email="pav@iki.fi",
url="https://numpydoc.readthedocs.io",
license="BSD",
- install_requires=["sphinx>=3.0", 'Jinja2>=2.10'],
+ install_requires=["sphinx>=3.0", "Jinja2>=2.10"],
python_requires=">=3.7",
extras_require={
"testing": [
- req for req in read('requirements/test.txt').split('\n')
- if not req.startswith('#')
+ req
+ for req in read("requirements/test.txt").split("\n")
+ if not req.startswith("#")
],
},
- package_data={'numpydoc': [
- 'tests/test_*.py',
- 'tests/tinybuild/Makefile',
- 'tests/tinybuild/index.rst',
- 'tests/tinybuild/*.py',
- 'templates/*.rst',
- ]},
+ package_data={
+ "numpydoc": [
+ "tests/test_*.py",
+ "tests/tinybuild/Makefile",
+ "tests/tinybuild/index.rst",
+ "tests/tinybuild/*.py",
+ "templates/*.rst",
+ ]
+ },
)