Skip to content

Add cross-reference links to parameter types #150

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions doc/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,53 @@ numpydoc_use_blockqutoes : bool
Until version 0.8, parameter definitions were shown as blockquotes, rather
than in a definition list. If your styling requires blockquotes, switch
this config option to True. This option will be removed in version 0.10.
numpydoc_xref_param_type : bool
Whether to create cross-references for the parameter types in the
``Parameters``, ``Other Parameters``, ``Returns`` and ``Yields``
sections of the docstring.
``True`` by default.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's opt-in, then this docstring should be changed to say "False by default"

numpydoc_xref_aliases : dict
Mappings to fully qualified paths (or correct ReST references) for the
aliases/shortcuts used when specifying the types of parameters.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention no spaces allowed

The keys should not have any spaces. Together with the ``intersphinx``
extension, you can map to links in any documentation.
The default is an empty ``dict``.

If you have the following ``intersphinx`` namespace configuration::

intersphinx_mapping = {
'python': ('https://docs.python.org/3/', None),
'numpy': ('https://docs.scipy.org/doc/numpy', None),
}

A useful ``dict`` may look like the following::

numpydoc_xref_aliases = {
# python
'sequence': ':term:`python:sequence`',
'iterable': ':term:`python:iterable`',
'string': 'str',
# numpy
'array': 'numpy.ndarray',
'dtype': 'numpy.dtype',
'ndarray': 'numpy.ndarray',
'matrix': 'numpy.matrix',
'array-like': ':term:`numpy:array_like`',
'array_like': ':term:`numpy:array_like`',
}

This option depends on the ``numpydoc_xref_param_type`` option
being ``True``.

numpydoc_xref_ignore : set
Words not to cross-reference. Most likely, these are common words
used in parameter type descriptions that may be confused for
classes of the same name. For example::

numpydoc_xref_ignore = {'type', 'optional', 'default'}

The default is an empty set.

numpydoc_edit_link : bool
.. deprecated:: edit your HTML template instead

Expand Down
14 changes: 14 additions & 0 deletions numpydoc/docscrape_sphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from sphinx.jinja2glue import BuiltinTemplateLoader

from .docscrape import NumpyDocString, FunctionDoc, ClassDoc
from .xref import make_xref_param_type

if sys.version_info[0] >= 3:
sixu = lambda s: s
Expand All @@ -33,6 +34,9 @@ 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.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')]
Expand Down Expand Up @@ -80,6 +84,11 @@ def _str_returns(self, name='Returns'):
out += ['']
for param, param_type, desc in self[name]:
if param_type:
if self.xref_param_type:
param_type = make_xref_param_type(
param_type,
self.xref_aliases,
self.xref_ignore)
out += self._str_indent([typed_fmt % (param.strip(),
param_type)])
else:
Expand Down Expand Up @@ -197,6 +206,11 @@ def _str_param_list(self, name, fake_autosummary=False):
fake_autosummary)

if param_type:
if self.xref_param_type:
param_type = make_xref_param_type(
param_type,
self.xref_aliases,
self.xref_ignore)
out += self._str_indent(['%s : %s' % (display_param,
param_type)])
else:
Expand Down
11 changes: 10 additions & 1 deletion numpydoc/numpydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
raise RuntimeError("Sphinx 1.0.1 or newer is required")

from .docscrape_sphinx import get_doc_object, SphinxDocString
from .xref import xref_param_type_role
from . import __version__

if sys.version_info[0] >= 3:
Expand Down Expand Up @@ -76,7 +77,11 @@ def mangle_docstrings(app, what, name, obj, options, lines):
'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}
'class_members_toctree': app.config.numpydoc_class_members_toctree,
'xref_param_type': app.config.numpydoc_xref_param_type,
'xref_aliases': app.config.numpydoc_xref_aliases,
'xref_ignore': app.config.numpydoc_xref_ignore,
}

u_NL = sixu('\n')
if what == 'module':
Expand Down Expand Up @@ -137,6 +142,7 @@ def setup(app, get_doc_object_=get_doc_object):
global get_doc_object
get_doc_object = get_doc_object_

app.add_role('xref_param_type', xref_param_type_role)
app.connect('autodoc-process-docstring', mangle_docstrings)
app.connect('autodoc-process-signature', mangle_signature)
app.add_config_value('numpydoc_edit_link', None, False)
Expand All @@ -146,6 +152,9 @@ def setup(app, get_doc_object_=get_doc_object):
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_xref_param_type', True, True)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the default is still True, so it's opt-out currently.

app.add_config_value('numpydoc_xref_aliases', dict(), True)
app.add_config_value('numpydoc_xref_ignore', set(), True)

# Extra mangling domains
app.add_domain(NumpyPythonDomain)
Expand Down
79 changes: 79 additions & 0 deletions numpydoc/tests/test_docscrape.py
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,85 @@ def test_templated_sections():
""")


xref_doc_txt = """
Test xref in Parameters, Other Parameters and Returns

Parameters
----------
p1 : int
Integer value

p2 : float, optional
Integer value

Other Parameters
----------------
p3 : list[int]
List of integers
p4 : :class:`pandas.DataFrame`
A dataframe
p5 : sequence of int
A sequence

Returns
-------
out : array
Numerical return value
"""


xref_doc_txt_expected = """
Test xref in Parameters, Other Parameters and Returns


:Parameters:

p1 : :xref_param_type:`int`
Integer value

p2 : :xref_param_type:`float`, optional
Integer value

:Returns:

out : :xref_param_type:`array <numpy.ndarray>`
Numerical return value


:Other Parameters:

p3 : :xref_param_type:`list`\[:xref_param_type:`int`]
List of integers

p4 : :class:`pandas.DataFrame`
A dataframe

p5 : :term:`python:sequence` of :xref_param_type:`int`
A sequence
"""


def test_xref():
xref_aliases = {
'sequence': ':term:`python:sequence`',
'iterable': ':term:`python:iterable`',
'array': 'numpy.ndarray',
}

xref_ignore = {'of', 'default', 'optional'}

doc = SphinxDocString(
xref_doc_txt,
config=dict(
xref_param_type=True,
xref_aliases=xref_aliases,
xref_ignore=xref_ignore
)
)

line_by_line_compare(str(doc), xref_doc_txt_expected)


if __name__ == "__main__":
import nose
nose.run()
128 changes: 128 additions & 0 deletions numpydoc/tests/test_xref.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# -*- encoding:utf-8 -*-
from __future__ import division, absolute_import, print_function

from nose.tools import assert_equal
from numpydoc.xref import make_xref_param_type

xref_aliases = {
# python
'sequence': ':term:`python:sequence`',
'iterable': ':term:`python:iterable`',
'string': 'str',
# numpy
'array': 'numpy.ndarray',
'dtype': 'numpy.dtype',
'ndarray': 'numpy.ndarray',
'matrix': 'numpy.matrix',
'array-like': ':term:`numpy:array_like`',
'array_like': ':term:`numpy:array_like`',
}

# Comes mainly from numpy
data = """
(...) array_like, float, optional
(...) :term:`numpy:array_like`, :xref_param_type:`float`, optional

(2,) ndarray
(2,) :xref_param_type:`ndarray <numpy.ndarray>`

(...,M,N) array_like
(...,M,N) :term:`numpy:array_like`

(..., M, N) array_like
(..., :xref_param_type:`M`, :xref_param_type:`N`) :term:`numpy:array_like`

(float, float), optional
(:xref_param_type:`float`, :xref_param_type:`float`), optional

1-D array or sequence
1-D :xref_param_type:`array <numpy.ndarray>` or :term:`python:sequence`

array of str or unicode-like
:xref_param_type:`array <numpy.ndarray>` of :xref_param_type:`str` or unicode-like

array_like of float
:term:`numpy:array_like` of :xref_param_type:`float`

bool or callable
:xref_param_type:`bool` or :xref_param_type:`callable`

int in [0, 255]
:xref_param_type:`int` in [0, 255]

int or None, optional
:xref_param_type:`int` or :xref_param_type:`None`, optional

list of str or array_like
:xref_param_type:`list` of :xref_param_type:`str` or :term:`numpy:array_like`

sequence of array_like
:term:`python:sequence` of :term:`numpy:array_like`

str or pathlib.Path
:xref_param_type:`str` or :xref_param_type:`pathlib.Path`

{'', string}, optional
{'', :xref_param_type:`string <str>`}, optional

{'C', 'F', 'A', or 'K'}, optional
{'C', 'F', 'A', or 'K'}, optional

{'linear', 'lower', 'higher', 'midpoint', 'nearest'}
{'linear', 'lower', 'higher', 'midpoint', 'nearest'}

{False, True, 'greedy', 'optimal'}
{:xref_param_type:`False`, :xref_param_type:`True`, 'greedy', 'optimal'}

{{'begin', 1}, {'end', 0}}, {string, int}
{{'begin', 1}, {'end', 0}}, {:xref_param_type:`string <str>`, :xref_param_type:`int`}

callable f'(x,*args)
:xref_param_type:`callable` f'(x,*args)

callable ``fhess(x, *args)``, optional
:xref_param_type:`callable` ``fhess(x, *args)``, optional

spmatrix (format: ``csr``, ``bsr``, ``dia`` or coo``)
:xref_param_type:`spmatrix` (format: ``csr``, ``bsr``, ``dia`` or coo``)

:ref:`strftime <strftime-strptime-behavior>`
:ref:`strftime <strftime-strptime-behavior>`

callable or :ref:`strftime <strftime-strptime-behavior>`
:xref_param_type:`callable` or :ref:`strftime <strftime-strptime-behavior>`

callable or :ref:`strftime behavior <strftime-strptime-behavior>`
:xref_param_type:`callable` or :ref:`strftime behavior <strftime-strptime-behavior>`

list(int)
:xref_param_type:`list`\(:xref_param_type:`int`)

list[int]
:xref_param_type:`list`\[:xref_param_type:`int`]

dict(str, int)
:xref_param_type:`dict`\(:xref_param_type:`str`, :xref_param_type:`int`)

dict[str, int]
:xref_param_type:`dict`\[:xref_param_type:`str`, :xref_param_type:`int`]

tuple(float, float)
:xref_param_type:`tuple`\(:xref_param_type:`float`, :xref_param_type:`float`)

dict[tuple(str, str), int]
:xref_param_type:`dict`\[:xref_param_type:`tuple`\(:xref_param_type:`str`, :xref_param_type:`str`), :xref_param_type:`int`]
""" # noqa: E501

xref_ignore = {'or', 'in', 'of', 'default', 'optional'}


def test_make_xref_param_type():
for s in data.strip().split('\n\n'):
param_type, expected_result = s.split('\n')
result = make_xref_param_type(
param_type,
xref_aliases,
xref_ignore
)
assert_equal(result, expected_result)
Loading