Formats¶
docshare reads and writes both NumPy and Google style, and detects which
one a docstring uses. The two produce the same internal representation, so a
Google-style function can inherit from a NumPy-style one and still be written
in its own style.
from docshare import docwrap
def numpy_source(x, y):
"""A source written in NumPy style.
Parameters
----------
x : int
The x, as the NumPy-style source describes it.
y : int
The y, as the NumPy-style source describes it.
"""
pass
@docwrap(inheritparams=numpy_source)
def f(x, y):
"""Written in Google style.
Args:
y (int): My own y.
"""
pass
assert 'Args:' in f.__doc__
assert 'x (int): The x, as the NumPy-style source describes it.' in f.__doc__
assert 'My own y.' in f.__doc__
format and render¶
format says what a docstring is; render says what to write.
@docwrap(format='numpy', render='google', inheritparams=numpy_source)
def g(x, y):
"""Written in NumPy style, written out in Google style.
Parameters
----------
y : int
My own y.
"""
pass
assert 'Args:' in g.__doc__
assert 'Parameters\n----------' not in g.__doc__
render defaults to format, or to the detected format when format was
not given. Giving render alone says how to write an object that has no
docstring to detect a format from:
@docwrap(render='numpy', inheritparams=numpy_source)
def h(x, y):
pass
assert h.__doc__.startswith('Parameters\n----------')
A docstring docshare cannot place — one that mixes both styles, or an
object with no docstring at all and no render — is an error rather than a
guess.
Items with no type¶
Google style lets a return value, a raised error, or a warning be described
without naming its type. The NumPy standard does not: its specification says
of Returns that “the type of each return value is always required”, and
repeats that for Yields. Converting therefore has to supply one, and
docshare writes the least specific type of the relevant hierarchy, which
asserts no more than the author did:
Section |
supplied type |
|---|---|
|
|
|
|
|
|
Returns: → Returns
The computed result. -------
object
The computed result.
Two consequences are worth knowing. Converting back to Google keeps the
supplied type, so a document that made the round trip says
object: The computed result. — nothing is lost, but it is not the
original text. And reading a NumPy docstring that puts prose where a type
belongs, which the standard does not allow, understands it as a description
and writes it back with a type. Both leave a docstring saying more than it
did, never less.
Recognizing that prose is a heuristic, and deliberately a narrow one. A
type cannot be told from a phrase by its shape: English words are valid
Python identifiers, so The computed result is built exactly like
array_like of float. What separates them is that a type is a noun phrase
and never closes a sentence. So a declaration that gives no name is read as a
description only when it ends with ., ?, or !, and anything else
keeps its meaning as a type. Types such as float, int, optional,
list of str, array_like of float, shape (n,), Sequence[int],
{'a', 'b'}, and ``:class:`numpy.ndarray``` are all unaffected. A type
written with a trailing full stop would be misread, which is the price of the
rule.
One ambiguity worth knowing about¶
A NumPy parameter written with an empty type has exactly the shape of a Google section header:
Parameters
----------
method :
Which method to use.
method : could be a parameter with no type, or the start of a Google
method: section. If the name also happens to be one docshare recognizes
as a section — method, args, params, returns, attributes,
notes, and a few dozen others — detection reports the ambiguity instead
of choosing.
Any of three things resolves it, and the error message says so:
method : str give the parameter a type
method or drop the colon
@docwrap(format='numpy', ...) or say which format the docstring is in
A parameter with a type is never ambiguous, so this only arises for a
dangling colon, and only for the few dozen names that are section titles. A
parameter named anything else — x :, method2 : — is read as the
declaration it is.
Prose that ends in a colon¶
A sentence introducing an indented block has the same shape as a Google section header, and sentences like this one are everywhere:
The tuple has the following elements:
a : the first
b : the second
docshare reads that as prose, because The tuple has the following elements is not the name of a Google section. Only the fixed set of Google
section titles opens a section, so ordinary prose is never mistaken for one
— and a document whose only colon block is prose is not a Google document
at all, so format='numpy' does not conflict with it.
The cost is described under
sections docshare does not recognize: a
Google document cannot spell a section docshare has never heard of unless
it is declared, which Custom sections describes.
Keyword arguments¶
Google style has a Keyword Args: section; the NumPy standard does not, and
documents keyword arguments in Parameters. The distinction is kept in the
model, so a Google document round-trips with it intact, and is merged only
when writing NumPy.
What rendering preserves¶
Rendering rewrites a document in the target format without rearranging or
discarding anything: the order of the sections and of the items within them,
grouped declarations, documented types, descriptions, and any section
docshare did not recognize are all carried across. The only changes are the
format-specific spellings — section titles, and the type that Google style
may omit but NumPy style requires.