Merge pull request #266 from xobs/add-moduledoc-autodoc
Add ModuleDoc and AutoDoc
This commit is contained in:
commit
836d5b88c5
|
@ -8,9 +8,9 @@ from migen import *
|
|||
|
||||
from litex.soc.interconnect.csr import *
|
||||
from litex.soc.interconnect.csr_eventmanager import *
|
||||
from litex.soc.integration.doc import ModuleDoc
|
||||
|
||||
|
||||
class Timer(Module, AutoCSR):
|
||||
class Timer(Module, AutoCSR, ModuleDoc):
|
||||
"""Timer
|
||||
|
||||
Provides a generic Timer core.
|
||||
|
@ -21,7 +21,7 @@ class Timer(Module, AutoCSR):
|
|||
- Periodic: (Re-)Loads itself when value reaches 0.
|
||||
|
||||
`en` register allows the user to enable/disable the Timer. When the Timer is enabled, it is
|
||||
automatically loaded with the value of `load' register.
|
||||
automatically loaded with the value of `load` register.
|
||||
|
||||
When the Timer reaches 0, it is automatically reloaded with value of `reload` register.
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
# This file is Copyright (c) 2019 Sean Cross <sean@xobs.io>
|
||||
|
||||
from migen.fhdl.module import DUID
|
||||
from migen.util.misc import xdir
|
||||
|
||||
from litex.soc.interconnect.csr_eventmanager import EventManager
|
||||
|
||||
import textwrap
|
||||
import inspect
|
||||
|
||||
class ModuleDoc(DUID):
|
||||
"""Module Documentation Support
|
||||
|
||||
ModuleDoc enables you to add documentation to your Module. This documentation is in addition to
|
||||
any CSR-level documentation you may add to your module, if applicable.
|
||||
|
||||
There are two ways to use :obj:`ModuleDoc`:
|
||||
|
||||
1. Inherit :obj:`ModuleDoc` as part of your class. The docstring of your class will become the
|
||||
first section of your class' module documentation
|
||||
2. Add a :obj:`ModuleDoc` object to your class and inherit from :obj:`AutoDoc`.
|
||||
|
||||
If you inherit from :obj:`ModuleDoc`, then there is no need to call ``__init__()``
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
class SomeClass(Module, ModuleDoc, AutoDoc):
|
||||
\"\"\"Some Special Hardware Module
|
||||
|
||||
This is a hardware module that implements something really cool.
|
||||
\"\"\"
|
||||
|
||||
def __init__(self):
|
||||
self.other_section = ModuleDoc(title="Protocol Details", body="This section details more
|
||||
information about the protocol")
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, body=None, title=None, file=None, format="rst"):
|
||||
"""Construct a :obj:`ModuleDoc` object for use with :obj:`AutoDoc`
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
body (:obj:`str`): Main body of the document. If ``title`` is omitted, then the
|
||||
title is taken as the first line of ``body``.
|
||||
|
||||
title (:obj:`str` Optional): Title of this particular section.
|
||||
|
||||
file (:obj:`str` Optional): It is possible to load the documentation from an external
|
||||
file instead of specifying it inline. This allows for the use of an external text
|
||||
editor. If a ``file`` is specified, then it will override the ``body`` argument.
|
||||
|
||||
format (:obj:`str` Optional): The text format. Python prefers reStructured Text, so this
|
||||
defaults to `rst`. If specifying a `file`, then the suffix will be used instead of
|
||||
`format`. If you specify a format other than `rst`, you may need to install a converter.
|
||||
"""
|
||||
|
||||
import os
|
||||
DUID.__init__(self)
|
||||
self._title = title
|
||||
self._format = format
|
||||
|
||||
if file == None and body == None and self.__doc__ is None:
|
||||
raise ValueError("Must specify `file` or `body` when constructing a ModuleDoc()")
|
||||
if file is not None:
|
||||
if not os.path.isabs(file):
|
||||
relative_path = inspect.stack()[1][1]
|
||||
file = os.path.dirname(relative_path) + os.path.sep + file
|
||||
(_, self._format) = os.path.splitext(file)
|
||||
self._format = self._format[1:] # Strip off "." from extension
|
||||
|
||||
# If it's a reStructured Text file, read the whole thing in.
|
||||
if self._format == "rst":
|
||||
with open(file, "r") as f:
|
||||
self.__doc__ = f.read()
|
||||
# Otherwise, we'll simply make a link to it and let sphinx take care of it
|
||||
else:
|
||||
self._path = file
|
||||
elif body is not None:
|
||||
self.__doc__ = body
|
||||
|
||||
def title(self):
|
||||
# This object might not have _title as an attribute, because
|
||||
# the ModuleDoc constructor may not have been called. If this
|
||||
# is the case, manipulate the __doc__ string directly.
|
||||
if hasattr(self, "_title") and self._title is not None:
|
||||
return self._title
|
||||
_lines = self.__doc__.splitlines()
|
||||
return textwrap.dedent(_lines[0])
|
||||
|
||||
def body(self):
|
||||
if hasattr(self, "_title") and self._title is not None:
|
||||
return self.__doc__
|
||||
_lines = self.__doc__.splitlines()
|
||||
_lines.pop(0)
|
||||
return textwrap.dedent("\n".join(_lines))
|
||||
|
||||
def format(self):
|
||||
if hasattr(self, "_format") and self._format is not None:
|
||||
return self._format
|
||||
return "rst"
|
||||
|
||||
def path(self):
|
||||
if hasattr(self, "_path"):
|
||||
return self._path
|
||||
return None
|
||||
|
||||
def documentationprefix(prefix, documents, done):
|
||||
for doc in documents:
|
||||
if doc.duid not in done:
|
||||
# doc.name = prefix + doc.name
|
||||
done.add(doc.duid)
|
||||
|
||||
def _make_gatherer(method, cls, prefix_cb):
|
||||
def gatherer(self):
|
||||
try:
|
||||
exclude = self.autodoc_exclude
|
||||
except AttributeError:
|
||||
exclude = {}
|
||||
try:
|
||||
prefixed = self.__prefixed
|
||||
except AttributeError:
|
||||
prefixed = self.__prefixed = set()
|
||||
r = []
|
||||
for k, v in xdir(self, True):
|
||||
if k not in exclude:
|
||||
if isinstance(v, cls):
|
||||
r.append(v)
|
||||
elif hasattr(v, method) and callable(getattr(v, method)):
|
||||
items = getattr(v, method)()
|
||||
prefix_cb(k + "_", items, prefixed)
|
||||
r += items
|
||||
return sorted(r, key=lambda x: x.duid)
|
||||
return gatherer
|
||||
|
||||
class AutoDoc:
|
||||
"""MixIn to provide documentation support.
|
||||
|
||||
A module can inherit from the ``AutoDoc`` class, which provides ``get_module_documentation``.
|
||||
This will iterate through all objects looking for ones that inherit from ModuleDoc.
|
||||
|
||||
If the module has child objects that implement ``get_module_documentation``,
|
||||
they will be called by the``AutoCSR`` methods and their documentation added to the lists returned,
|
||||
with the child objects' names as prefixes.
|
||||
"""
|
||||
get_module_documentation = _make_gatherer("get_module_documentation", ModuleDoc, documentationprefix)
|
Loading…
Reference in New Issue