paths_cli/compiling/_gendocs/docs_generator.py
import sys
from paths_cli.compiling.core import Parameter
from .json_type_handlers import json_type_to_string
from .config_handler import DocCategoryInfo
PARAMETER_RST = """* **{p.name}**{type_str} - {p.description}{required}\n"""
class DocsGenerator:
"""This generates the RST to describe options for compile input files.
Parameters
----------
config : Dict[str, DocCategoryInfo]
mapping of category name to DocCategoryInfo for that category;
usually generated by :method:`.load_config`
"""
parameter_template = PARAMETER_RST
_ANCHOR_SEP = "--"
def __init__(self, config):
self.config = config
def format_parameter(self, parameter, type_str=None):
"""Format a single :class:`.paths_cli.compiling.Parameter` in RST
"""
required = " (required)" if parameter.required else ""
return self.parameter_template.format(
p=parameter, type_str=type_str, required=required
)
def _get_cat_info(self, category_plugin):
cat_info = self.config.get(category_plugin.label, None)
if cat_info is None:
cat_info = DocCategoryInfo(category_plugin.label)
return cat_info
def generate_category_rst(self, category_plugin):
"""Generate the RST for a given category plugin.
Parameters
----------
category_plugin : :class:`.CategoryPlugin`
the plugin for which we should generate the RST page
Returns
-------
str :
RST string for this category
"""
cat_info = self._get_cat_info(category_plugin)
type_required = cat_info.type_required
rst = f".. _compiling--{category_plugin.label}:\n\n"
rst += f"{cat_info.header}\n{'=' * len(str(cat_info.header))}\n\n"
if cat_info.description:
rst += cat_info.description + "The following types are available:\n\n"
rst += ".. contents:: :local:\n\n"
for obj in category_plugin.type_dispatch.values():
rst += self.generate_plugin_rst(
obj, category_plugin.label, type_required
)
return rst
def generate_plugin_rst(self, plugin, category_name,
type_required=True):
"""Generate the RST for a given object plugin.
Parameters
----------
plugin : class:`.InstanceCompilerPlugin`
the object plugin for to generate the RST for
category_name : str
the name of the category for this object
type_required : bool
whether the ``type`` parameter is required in the dict input for
compiling this type of object (usually category-dependent)
Returns
-------
str :
RST string for this object plugin
"""
rst_anchor = f".. _{category_name}{self._ANCHOR_SEP}{plugin.name}:"
rst = f"{rst_anchor}\n\n{plugin.name}\n{'-' * len(plugin.name)}\n\n"
if plugin.description:
rst += plugin.description + "\n\n"
if type_required:
type_param = Parameter(
"type",
json_type="",
loader=None,
description=(f"type identifier; must exactly match the "
f"string ``{plugin.name}``"),
)
rst += self.format_parameter(
type_param, type_str=""
)
name_param = Parameter(
"name",
json_type="string",
loader=None,
default="",
description="name this object in order to reuse it",
)
rst += self.format_parameter(name_param, type_str=" (string)")
for param in plugin.parameters:
type_str = f" ({json_type_to_string(param.json_type)})"
rst += self.format_parameter(param, type_str)
rst += "\n\n"
return rst
@staticmethod
def _get_filename(cat_info):
fname = str(cat_info.header).lower()
fname = fname.translate(str.maketrans(' ', '_'))
return f"{fname}.rst"
def generate(self, category_plugins, stdout=False):
"""Generate RST output for the given plugins.
This is the main method used to generate the entire set of
documentation.
Parameters
----------
category_plugin : List[:class:`.CategoryPlugin`]
list of category plugins document
stdout : bool
if False (default) a separate output file is generated for each
category plugin. If True, all text is output to stdout
(particularly useful for debugging/dry runs).
"""
for plugin in category_plugins:
rst = self.generate_category_rst(plugin)
if stdout:
sys.stdout.write(rst)
sys.stdout.flush()
else:
cat_info = self._get_cat_info(plugin)
filename = self._get_filename(cat_info)
with open(filename, 'w') as f:
f.write(rst)