Using MkApi within Python
MkApi is a standalone library as well as a MkDocs plugin, so that you can use it within Python.
First, import MkApi:
import mkapi
[1] 2020-12-20 11:36:13 (93.8ms) python3 (633ms)
Node object
Define a simple class to show how MkApi works.
class A:
"""Class docstring.
Note:
Docstring of `__init__()` is deleted, if there is
a class-level docstring.
"""
def __init__(self):
"""Init docstring."""
self.a: int = 1 #: Integer **attribute**.
def to_str(self, x: int) -> str:
"""Converts `int` to `str`.
Args:
x: Input **value**.
"""
return str(x)
[2] 2020-12-20 11:36:13 (15.6ms) python3 (649ms)
mkapi.get_node()
generates a Node
object that has tree structure.
node = mkapi.get_node(A)
type(node)
[3] 2020-12-20 11:36:13 (15.6ms) python3 (664ms)
mkapi.core.node.Node
Some attributes:
node.object.kind, node.object.name
[4] 2020-12-20 11:36:13 (15.6ms) python3 (680ms)
('class', 'A')
docstring = node.docstring
len(docstring.sections)
[5] 2020-12-20 11:36:13 (15.6ms) python3 (696ms)
1
section = docstring.sections[0]
section.name
[6] 2020-12-20 11:36:13 (15.6ms) python3 (711ms)
''
print(section.markdown)
[7] 2020-12-20 11:36:13 (15.6ms) python3 (727ms)
Class docstring.
!!! note "Note"
Docstring of `__init__()` is deleted, if there is
a class-level docstring.
The members
attribute gives children, for example, bound methods of a class.
len(node.members)
[8] 2020-12-20 11:36:13 (15.6ms) python3 (742ms)
1
child = node.members[0]
type(child)
[9] 2020-12-20 11:36:13 (15.6ms) python3 (758ms)
mkapi.core.node.Node
Elements of Node.members
are also Node
objects, so this is a tree structure.
child.object.kind, child.object.name
[10] 2020-12-20 11:36:13 (15.6ms) python3 (774ms)
('method', 'to_str')
docstring = child.docstring
len(docstring.sections)
[11] 2020-12-20 11:36:13 (15.6ms) python3 (789ms)
2
section = docstring.sections[0]
section.name, section.markdown
[12] 2020-12-20 11:36:13 (15.6ms) python3 (805ms)
('', 'Converts `int` to `str`.')
section = docstring.sections[1]
section.name, section.markdown
[13] 2020-12-20 11:36:13 (15.6ms) python3 (821ms)
('Parameters', '')
The above Parameters section has an empty markdown
, while its items
represents an argument list:
item = section.items[0]
print(item)
print(item.type)
print(item.description)
[14] 2020-12-20 11:36:13 (15.6ms) python3 (836ms)
Item('x', 'int')
Type('int')
Inline('Input **value**.')
Node.get_markdown()
creates a joint Markdown of this node.
markdown = node.get_markdown()
print(markdown)
[15] 2020-12-20 11:36:13 (15.6ms) python3 (852ms)
A
<!-- mkapi:sep -->
Class docstring.
!!! note "Note"
Docstring of `__init__()` is deleted, if there is
a class-level docstring.
<!-- mkapi:sep -->
__main__.A.to_str
<!-- mkapi:sep -->
Converts `int` to `str`.
<!-- mkapi:sep -->
Input **value**.
Where is Note or Parameters section heading, etc.? No problem. The Node.get_markdown()
divides docstrings into two parts. One is a plain Markdown that will be converted into HTML by any Markdown converter, for example, MkDocs. The other is the outline structure of docstrings such as sections or arguments that will be processed by MkApi itself.
Converting Markdown
For simplicity, we use Python-Markdown library instead of MkDocs.
from markdown import Markdown
converter = Markdown(extensions=['admonition'])
html = converter.convert(markdown)
print(html)
[16] 2020-12-20 11:36:13 (15.6ms) python3 (867ms)
<p><a href="!A">A</a></p>
<!-- mkapi:sep -->
<p>Class docstring.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Docstring of <code>__init__()</code> is deleted, if there is
a class-level docstring.</p>
</div>
<!-- mkapi:sep -->
<p><a href="!__main__.A"><strong>main</strong>.A</a>.<a href="!__main__.A.to_str">to_str</a></p>
<!-- mkapi:sep -->
<p>Converts <code>int</code> to <code>str</code>.</p>
<!-- mkapi:sep -->
<p>Input <strong>value</strong>.</p>
Distributing HTML
Node.set_html()
distributes HTML into docstring and members.
node.set_html(html)
[17] 2020-12-20 11:36:13 (15.6ms) python3 (883ms)
Take a look at what happened.
section = node.docstring.sections[0]
section.markdown, section.html
[18] 2020-12-20 11:36:13 (15.6ms) python3 (899ms)
('Class docstring.\n\n!!! note "Note"\n Docstring of `__init__()` is deleted, if there is\n a class-level docstring.',
'<p>Class docstring.</p>\n<div class="admonition note">\n<p class="admonition-title">Note</p>\n<p>Docstring of <code>__init__()</code> is deleted, if there is\na class-level docstring.</p>\n</div>')
child = node.members[0]
section = child.docstring.sections[0]
section.markdown, section.html
[19] 2020-12-20 11:36:13 (15.6ms) python3 (914ms)
('Converts `int` to `str`.',
'<p>Converts <code>int</code> to <code>str</code>.</p>')
section = child.docstring.sections[1]
item = section.items[0]
item.description.markdown, item.description.html # A <p> tag is deleted.
[20] 2020-12-20 11:36:13 (15.6ms) python3 (930ms)
('Input **value**.', 'Input <strong>value</strong>.')
Constructing HTML
Finally, construct HTML calling Node.get_html()
that internally uses Jinja library.
html = node.get_html()
print(html[:300].strip())
[21] 2020-12-20 11:36:13 (77.8ms) python3 (1.01s)
<div class="mkapi-node" id="A">
<div class='mkapi-object-container'>
<div class="mkapi-object class code top">
<div class="mkapi-object-kind class top">class</div>
<div class="mkapi-object-body class top"><code class="mkapi-object-name">A</code><code class="mkapi-object-parenthesis">(</cod
Jupyter allows us to see the rendered HTML.
from IPython.display import HTML
HTML(html)
[22] 2020-12-20 11:36:13 (13.0ms) python3 (1.02s)
A
(
)
Class docstring.
Note
Docstring of __init__()
is deleted, if there is
a class-level docstring.
to_str
(
x
)
→ strConverts int
to str
.
x
(int) — Input value.
Summary
All you need to get the documentation of an object is described by the following function.
from markdown import Markdown
import mkapi
def get_html(obj) -> str:
# Construct a node tree structure.
node = mkapi.get_node(obj)
# Create a joint Markdown from components of the node.
markdown = node.get_markdown()
# Convert it into HTML by any external converter.
converter = Markdown()
html = converter.convert(markdown)
# Split and distribute the HTML into original components.
node.set_html(html)
# Render the node to create final HTML.
return node.get_html()
[23] 2020-12-20 11:36:13 (16.7ms) python3 (1.04s)