Inspecting docstrings

quartodoc uses the library griffe to load and parse docstrings.

Docstring structure

quartodoc currently expects docstrings to be in the numpydocstring format.

Docstrings are loaded and parsed using griffe, which uses custom data classes to represent the structure of a program:

Reading docstrings

Use the function get_object to read in a docstring from a module.

from quartodoc import get_object, preview

f_obj = get_object("quartodoc", "get_object")
f_obj
Alias('get_object', 'quartodoc.autosummary.get_object')

The result above is a griffe object representing the function quartodoc.get_object, which has two important attributes:

  • .name: the function’s name.
  • .parameters: the function’s parameters.
  • .docstring.value: the actual docstring
  • .docstring.parsed: the docstring parsed into a tree of griffe objects

Function name

f_obj.name
'get_object'

Function parameters

f_obj.parameters
Parameters(Parameter(name='path', annotation=ExprName(name='str', parent=Module(PosixPath('/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/quartodoc/autosummary.py'))), kind=<ParameterKind.positional_or_keyword: 'positional or keyword'>, default=None), Parameter(name='object_name', annotation="'str | None'", kind=<ParameterKind.positional_or_keyword: 'positional or keyword'>, default='None'), Parameter(name='parser', annotation=ExprName(name='str', parent=Module(PosixPath('/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/quartodoc/autosummary.py'))), kind=<ParameterKind.positional_or_keyword: 'positional or keyword'>, default="'numpy'"), Parameter(name='load_aliases', annotation=None, kind=<ParameterKind.positional_or_keyword: 'positional or keyword'>, default='True'), Parameter(name='dynamic', annotation=None, kind=<ParameterKind.positional_or_keyword: 'positional or keyword'>, default='False'), Parameter(name='loader', annotation=ExprBinOp(left='None', operator='|', right=ExprName(name='GriffeLoader', parent=Module(PosixPath('/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/quartodoc/autosummary.py')))), kind=<ParameterKind.positional_or_keyword: 'positional or keyword'>, default='None'))

Raw docstring value

print(f_obj.docstring.value)
Fetch a griffe object.

Parameters
----------
path: str
    An import path to the object. This should have the form `path.to.module:object`.
    For example, `quartodoc:get_object` or `quartodoc:MdRenderer.render`.
object_name: str
    (Deprecated). A function name.
parser: str
    A docstring parser to use.
load_aliases: bool
    For aliases that were imported from other modules, should we load that module?
dynamic: bool
    Whether to dynamically import object. Useful if docstring is not hard-coded,
    but was set on object by running python code.

See Also
--------
preview: print a user-friendly preview of a griffe object.

Examples
--------

>>> get_function("quartodoc", "get_function")
<Function('get_function', ...

Returns
-------
x:
    abc

Parsed docstring

f_obj.docstring.parsed
[<_griffe.docstrings.models.DocstringSectionText at 0x7f6c985f74f0>,
 <_griffe.docstrings.models.DocstringSectionParameters at 0x7f6c985f7850>,
 <_griffe.docstrings.models.DocstringSectionAdmonition at 0x7f6c985f7730>,
 <_griffe.docstrings.models.DocstringSectionExamples at 0x7f6c985f7640>,
 <_griffe.docstrings.models.DocstringSectionReturns at 0x7f6c985f73a0>]

The docstring into a tree lets us define visitors, which can visit each element and do useful things. For example, print a high-level overview of its structure, or render it to markdown.

Previewing docstrings

Use the preview function to see the overall structure of a parsed docstring.

from quartodoc import get_object, preview

f_obj = get_object("quartodoc", "get_object")

Raw docstring

print(f_obj.docstring.value)
Fetch a griffe object.

Parameters
----------
path: str
    An import path to the object. This should have the form `path.to.module:object`.
    For example, `quartodoc:get_object` or `quartodoc:MdRenderer.render`.
object_name: str
    (Deprecated). A function name.
parser: str
    A docstring parser to use.
load_aliases: bool
    For aliases that were imported from other modules, should we load that module?
dynamic: bool
    Whether to dynamically import object. Useful if docstring is not hard-coded,
    but was set on object by running python code.

See Also
--------
preview: print a user-friendly preview of a griffe object.

Examples
--------

>>> get_function("quartodoc", "get_function")
<Function('get_function', ...

Returns
-------
x:
    abc

Preview

preview(f_obj.docstring.parsed)
█─list
├─0 = █─DocstringSectionText
│     ├─kind = <DocstringSectionKind.text: 'text'>
│     ├─title = None
│     └─value = 'Fetch a griffe object.'
├─1 = █─DocstringSectionParameters
│     ├─kind = <DocstringSectionKind.parameters: 'parameters'>
│     ├─title = None
│     └─value = █─list
│               ├─0 = █─DocstringParameter
│               │     ├─annotation = ExprName(name='str', parent=Module(PosixPath('/opt ...
│               │     ├─default = None
│               │     ├─description = 'An import path to the object. This should have th ...
│               │     ├─name = 'path'
│               │     └─value = None
│               ├─1 = █─DocstringParameter
│               │     ├─annotation = "'str | None'"
│               │     ├─default = 'None'
│               │     ├─description = '(Deprecated). A function name.'
│               │     ├─name = 'object_name'
│               │     └─value = 'None'
│               ├─2 = █─DocstringParameter
│               │     ├─annotation = ExprName(name='str', parent=Module(PosixPath('/opt ...
│               │     ├─default = "'numpy'"
│               │     ├─description = 'A docstring parser to use.'
│               │     ├─name = 'parser'
│               │     └─value = "'numpy'"
│               ├─3 = █─DocstringParameter
│               │     ├─annotation = None
│               │     ├─default = 'True'
│               │     ├─description = 'For aliases that were imported from other modules ...
│               │     ├─name = 'load_aliases'
│               │     └─value = 'True'
│               └─4 = █─DocstringParameter
│                     ├─annotation = None
│                     ├─default = 'False'
│                     ├─description = 'Whether to dynamically import object. Useful if d ...
│                     ├─name = 'dynamic'
│                     └─value = 'False'
├─2 = █─DocstringSectionSeeAlso
│     ├─kind = <DocstringSectionKindPatched.see_also: 'see also'>
│     ├─title = 'See Also'
│     └─value = 'preview: print a user-friendly preview of a griff ...
├─3 = █─DocstringSectionExamples
│     ├─kind = <DocstringSectionKind.examples: 'examples'>
│     ├─title = None
│     └─value = █─list
│               └─0 = █─ExampleCode
│                     └─value = '>>> get_function("quartodoc", "get_function")\n<F ...
└─4 = █─DocstringSectionReturns
      ├─kind = <DocstringSectionKind.returns: 'returns'>
      ├─title = None
      └─value = █─list
                └─0 = █─DocstringReturn
                      ├─name = 'x'
                      ├─annotation = ExprAttribute(values=[ExprName(name='dc', parent=M ...
                      └─description = 'abc'

Parsing other docstring formats

Currently, quartodoc expects docstrings in the numpydoc format. However, the tool it uses under the hood (griffe) is easy to customize, and supports multiple formats.

See the griffe loading docs for instructions. Specifically, the GriffeLoader takes options for customizing docstring parsing.