Getting started
When using the Pydoc-Markdown integration with Novella to make use of its Markdown pre-processing capabilities,
Pydoc-Markdown comes as a plugin that provides a @pydoc and @pylink tag to insert Markdown documentation
generated by Pydoc-Markdown in the corresponding places of your documentation.
Installation
When using Pipx, the recommended installation method is to inject Pydoc-Markdown later:
$ pipx install novella
$ pipx inject novella pydoc-markdown[novella]
If you manage the environment yourself, it's sufficient to install Pydoc-Markdown with the novella extra.
$ pip install pydoc-markdown[novella]
Configuration
A Novella build is configured using a build.novella script. In most cases you want to rely on a template provided
by Novella, such as the MkDocs template. Check out the Novella documentation to find what types of templates
are available here.
template "mkdocs" {
content_directory = "content"
}
action "preprocess-markdown" {
use "pydoc"
}
What is happening here?
- The
mkdocspipeline template is applied. Thecontent_directoryis the directory that contains your MkDocs source files. It will be copied to the temporary build location alongside themkdocs.ymlfile. Note that yourbuild.novellascript should sit next two these files.
Note: You should have
mkdocson yourPATHand it should have themkdocs-materialtheme installed (the default theme that Novella will apply if you don't specify a different one in yourmkdocs.ymlfile or inbuild.novella).
- The
preprocess-markdownaction that is one of the actions created by the template is retrieved and configured further. We instruct it to make use of the"pydoc"plugin, which is implemented by Pydoc-Markdown and provides the@pydocand{@link pydoc:}tags.
Note
-
The
content/directory is the default so it does not need to be set explicitly and it is sufficient to writetemplate "mkdocs"(without an empty configuration block). -
The
mkdocstemplate will apply a default configuration delivered with Novella to your MkDocs configuration. If you don't want this, you can configure the"mkdocs-update-config"action to disable this. Note that you can also have no MkDocs configuration file and the template will create a default file for you. -
The
pydoctag is implemented in {@link pydoc:pydoc_markdown.novella.preprocessor.PydocTagPreprocessor}. Look it up to understand how it can be configured further. -
The
pydoctag processor applies a heuristic to populate the default search path for your Python source code. If the directory in which the build is executed is calleddocsordocumentation, it will default to[ "../src", ".." ], otherwise it will default to[ "src", "." ].
Using Novella tags
For example, the @cat tag is useful to inject the content of another file.
# Welcome to my Project documentation!
@cat ../../readme.md :with slice_lines = "2:"
The @pydoc tag is the piece provided by Pydoc-Markdown itself. It uses the Class MarkdownRenderer to generate Markdown formatted API documentation of
the API object you specify.
# API Documentation
@pydoc my_module.SomeClass
Build the documentation
Change into the docs/ directory where your build.novella script resides and invoke the Novella CLI. The MkDocs
template exposes some command-line arguments that you can pass through the CLI, one of which is the --serve option
that runs MkDocs in the server mode instead of building the documentation and writing it to disk.
usage: novella [--version] [-h] [-i TEMPLATE] [-c PATH] [-d DIRECTORY]
[-b PATH] [-r] [--dot] [--intercept ACTION] [--serve]
[--port PORT] [--site-dir PATH] [--base-url URL]
options:
--version show program's version number and exit
-h, --help Show this help output.
-i TEMPLATE, --init TEMPLATE
Create a `build.novella` file initialized from a
template. Available templates are: "mkdocs", "hugo"
-c PATH, --config-file PATH
The configuration file to load. Can be a
pyproject.toml in which case the code is looked up
under the tool.novella.script key. (default: None)
-d DIRECTORY, --directory DIRECTORY
Switch to the specified directory before executing the
configuration file.
-b PATH, --build-directory PATH
The build directory. If not specified, a temporary
directory will be created.
-r, --use-reloader Enable reloading, which will re-execute the pipeline
if a watched file changes.
--dot Produce a DotViz representation of the build graph.
--intercept ACTION The name of an action to intercept and pause the
execution, waiting for user input to continue. Useful
for debugging intermediate steps of the build process.
Currently, the action name must be matched exactly and
actions can only be intercepted before they are run.
If this option is provided, all possible intercept
points are logged to the console.
template (mkdocs):
--serve Use mkdocs serve
--port PORT The port to serve under
--site-dir PATH Build directory for MkDocs (defaults to "_site")
--base-url URL The base URL to prefix to autogenerated link inside
the documentation.
Advantages over the YAML Configuration
The YAML Configuration allows you to define in one file all pages and the Python API objects they should contain. However, when you use Novella, each page will need to exist as a Markdown file. This has a few advantages:
- Easier to understand; The YAML
pagesconfiguration could be hard to reason about, while having an actual file for each page is much more human friendly and actually resembles the project structure for the static site generator in use. - 1-to-1 mapping; Each page in the final documentation is represented by a file in the source project, allowing things like the "Edit URL" generated by MkDocs to point to the actual page source rather than a 404 page.
- Mixing static and generated content; Placing generated API documentation where the
@pydoctag is used in the Markdown page allows you to put static documentation content around it.
Now, if you still want to generate Markdown files at build time, Pydoc-Markdown does not currently provide any functionality to do that; although some discussion around the topic is happening in #245. However, the Novella build script is just code, so if you really need it, you can generate the files there:
template "mkdocs"
def api_pages = {
"SomeClass": "my_module.SomeClass",
# ...
}
action "mkdocs-update-config" {
site_name = "My module"
profile = "readthedocs"
update_with config -> {
def items = []
for title, package in api_pages.items():
items.append({ title: 'api/{}.md'.format(package) })
config['nav'].append({ 'API Documentation': items })
}
}
action "preprocess-markdown" {
use "pydoc"
}
do
name: "generate-api-pages"
closure: {
# Make sure that this action runs before the Markdown preprocessors.
precedes "preprocess-markdown"
}
action: {
for title, package in api_pages.items():
def path = directory / 'content' / 'api' / (package + '.md')
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text('---\ntitle: {}\n---\n@pydoc {}\n'.format(title, package))
}