astutus.sphinx package¶
A Sphinx extension for styled, dynamic web pages with Flask web applications.
Overview¶
At this time, the extension is targeted at the sphinx_rtd_theme Sphinx theme.
At this time, the Sphinx extension is not designed to be installed separately from the Astutus python package.
Configuration¶
The package can be used by adding this line into your Sphinx documentation conf.py file:
extensions = [
...,
'astutus.sphinx.dyn_pages',
]
In addition, you need to add the extension’s CSS file into you _static folder:
astutus_dynamic_sphinx_pages.css
There are a number of configuration variables that must be defined:
# Options for the Astutus dynamic pages custom extension.
astutus_dyn_pages_dir = "app" # relative to the configuration directory.
astutus_dyn_base = "/your_applications_urls_leading_path" # web app URL path to get to top of dynamic pages.
astutus_dyn_extra_head_material = " what every you want to add in the HTML head section of dynamic pages. "
Optional configuration variables have good-enough default values that it is not expected that user’s of the extension will need to customize them. At this time, the extension has one optional configuration variable:
astutus_dyn_styled_templates_path = ‘astutus_dyn_styled_templates’
Directives¶
The directives implemented are:
.. astutus_dyn_include:: use Jinja2 template in a styled page
.. astutus_dyn_link:: fix up the ..toc_tree:: directive to work with the page
.. astutus_dyn_bookmark:: customize the browser bookmark (and tab title) for a page
.. astutus_dyn_breadcrumb:: customize the Read-the-Docs breadcrumb navigation for a page
.. astutus_dyn_destination:: place the styled template in a particular location
.. astutus_toggle_note:: write a note that can be expanded or collapsed
Submodules¶
astutus.sphinx.dyn_pages module¶
-
class
astutus.sphinx.dyn_pages.
BookmarkDirective
(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)¶ Bases:
sphinx.util.docutils.SphinxDirective
Implements the .. astutus_dyn_bookmark:: directive.
This directive allows customizing the title tag in the head section of the HTML tag. This tag is used in labeling browser tabs and suggested values for browser book marks.
The one required argument specifies replacement bookmark text.
The argument can contain values in angled brackets that are translated into Jinja2 variables. This is useful when corresponding page should be dynamically labeled.
The directive should be used once on a particular page, if the default bookmark is not adequate.
-
final_argument_whitespace
= True¶
-
static
handle_insert_markup
(app: sphinx.application.Sphinx, doctree, fromdocname: str) → None¶ Handle title modification by inserting post processing markup in the doctree.
-
required_arguments
= 1¶
-
run
() → List[astutus.sphinx.dyn_pages.BookmarkNode]¶ Replaces the directive in the *.rst file with a BookMarkNode.
-
-
class
astutus.sphinx.dyn_pages.
BookmarkNode
(rawsource='', *children, **attributes)¶ Bases:
docutils.nodes.General
,docutils.nodes.Element
Stores the processed value of the argument to the directive.
-
class
astutus.sphinx.dyn_pages.
BreadCrumbDirective
(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)¶ Bases:
sphinx.util.docutils.SphinxDirective
Implements the .. astutus_dyn_breadcrumb:: directive.
This directive allows overriding the final entry in the breadcrumb navigation displayed by the Read-the-Docs theme near the top of the page. The last entry is for the current page, and is static text, rather than being a link like the rest of the breadcrumbs.
This directive is optional, and is typically used for item pages where the value normally derived from the title of the page is not informative. It should only be used once on a dynamic page.
- Usage:
.. astutus_dyn_breadcrumb:: breadcrumb_text
The breadcrumb text may contain whitespace and variables marked with angle brackets.
-
final_argument_whitespace
= True¶
-
static
handle_insert_markup
(app: sphinx.application.Sphinx, doctree, fromdocname)¶
-
required_arguments
= 1¶
-
run
() → List[astutus.sphinx.dyn_pages.BreadCrumbNode]¶
-
class
astutus.sphinx.dyn_pages.
BreadCrumbNode
(rawsource='', *children, **attributes)¶ Bases:
docutils.nodes.General
,docutils.nodes.Element
Stores the processed value of the argument to the directive.
-
class
astutus.sphinx.dyn_pages.
DestinationDirective
(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)¶ Bases:
sphinx.util.docutils.SphinxDirective
Implements the .. astutus_dyn_destintation:: directive.
The one required argument specifies a relative filepath where to write the styled template.
Its optional, and is for the convenience of the web developer. In most cases, the default location based on the name and location the dynamic page.
-
static
handle_insert_markup
(app: sphinx.application.Sphinx, doctree, fromdocname) → None¶ Handle title modification by inserting post processing markup.
-
required_arguments
= 1¶
-
run
() → List[docutils.nodes.Node]¶ Replaces the directive in the *.rst file with a DestinationNode.
-
static
-
class
astutus.sphinx.dyn_pages.
DestinationNode
(rawsource='', *children, **attributes)¶ Bases:
docutils.nodes.General
,docutils.nodes.Element
Stores the processed value of the argument to the directive.
-
class
astutus.sphinx.dyn_pages.
IncludeDirective
(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)¶ Bases:
sphinx.util.docutils.SphinxDirective
Implements the .. astutus_dyn_include:: directive.
This directive allows inserting functional Jinja2 templates into the styled template generated for dynamic pages.
The one required argument specifies a relative filepath to locate the template within the template directory of the Flask application.
This directive is optional. It may be used multiple times on a dynamic page as needed for the layout of the page.
-
static
handle_insert_markup
(app: sphinx.application.Sphinx, doctree, fromdocname) → None¶ Handle include modification by inserting post processing markup.
-
required_arguments
= 1¶
-
run
() → List[docutils.nodes.Node]¶ Replaces the directive in the *.rst file with a IncludeNode.
-
static
-
class
astutus.sphinx.dyn_pages.
IncludeNode
(rawsource='', *children, **attributes)¶ Bases:
docutils.nodes.General
,docutils.nodes.Element
Stores the processed value of the argument to the directive.
-
class
astutus.sphinx.dyn_pages.
LinkDirective
(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)¶ Bases:
sphinx.util.docutils.SphinxDirective
Implements the .. astutus_dyn_link:: directive.
- Usage:
.. astutus_dyn_link:: link_path [link_replacement_text]
The replacement text may contain whitespace.
This directive is required on all dynamic styled pages.
-
final_argument_whitespace
= True¶
-
optional_arguments
= 1¶
-
required_arguments
= 1¶
-
run
() → List[docutils.nodes.Node]¶ Processes the astutus_dyn_link directive arguments and stores them in the environmment.
No node is added to the docutils doctree.
-
class
astutus.sphinx.dyn_pages.
ToggleNoteDirective
(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)¶ Bases:
sphinx.util.docutils.SphinxDirective
Implements a note directive that allows the content of the note to be collapsed by the browser user.
Usage:
.. astutus_toggle_note:: [ expanded|collapsed [extra_title_text]]
indented block of text for note …
If the first argument is omitted, it defaults to expanded.
If extra_title_text is to be provided, the author must explicitly specify the toggle state. The argument extra_title_text may contain whitespace.
This directive does not require support from Flask. It is implemented using CSS and HTML. It can be used on any page.
-
final_argument_whitespace
= True¶
-
static
handle_insert_markup
(app: sphinx.application.Sphinx, doctree, fromdocname) → None¶ This method converts any ToggleNoteNodes into docutil nodes for HTML.
-
has_content
= True¶
-
optional_arguments
= 2¶
-
run
() → List[astutus.sphinx.dyn_pages.ToggleNoteNode]¶ Parses the directive when encountered in a *.rst file.
At the time this method is called, the arguments, options, and content for the directive have been store in initializing the directive object. This method returns a list containing any nodes to be inserted into the Docutils document.
For this directive, all useful directive values are stored in a single specialized node for subsequent processing after the document tree has been resolved.
-
-
class
astutus.sphinx.dyn_pages.
ToggleNoteNode
(rawsource='', *children, **attributes)¶ Bases:
docutils.nodes.note
Stores the processed values of the arguments and content of the directive.
-
astutus.sphinx.dyn_pages.
config_inited
(app: sphinx.application.Sphinx, config: sphinx.config.Config) → None¶ Check that the required configuration variables have been initialized
-
astutus.sphinx.dyn_pages.
create_post_processing_markup
(tag: str, value: str) → str¶ Create the markup to be embedded in the HTML used to communicate to the post processor.
At this time, the markup looks like this: ««TAG»»value««END_TAG»»
-
astutus.sphinx.dyn_pages.
depart_generic_node
(self, node)¶ Does nothing.
-
astutus.sphinx.dyn_pages.
log_as_info
(msg: str) → None¶ Convenience function to log with colored output if desired for development or debugging.
-
astutus.sphinx.dyn_pages.
post_processing_mark_found
(tag: str, text: str) → bool¶ Search the text for the post processing directive identified by the tag. Returns true if found.
-
astutus.sphinx.dyn_pages.
read_post_processing_directive_value
(tag: str, text: str) → str¶ Searches the text for the post processing directive identified by the tag, and return the value.
Returns None if the tag is not found.
-
astutus.sphinx.dyn_pages.
setup
(app: sphinx.application.Sphinx) → Tuple¶ This is the standard set function for the extension.
It specifies extension configuration values, directives implemented by the extension, nodes used in processing the directives, and the connection between Sphinx events and the functions that implement the extension.
-
astutus.sphinx.dyn_pages.
visit_generic_node
(self, node)¶ Does nothing.
astutus.sphinx.post_process module¶
Handle the post processing step that converts the styled html pages to Jinja2 templates.
Implementation¶
At this time, the details of how the toctree directive works are not understood, nor the process by which the html writer interacts with the theme. Consequently, for pragmatic reasons, instead of creating a specialized builder or writer, the insertion of Jinja2 markup for use in the Flask application is handled as a post processing step.
The information needed for this step comes from post processing “directive markup” embedded in Sphinx generated documents, as well as Sphinx application configuration and environment values.
The markup is described in astutus.sphinx.dyn_pages module documentation.
The resulting Jinja templates are stored in a distinct subdirectory directory within the Sphinx _build directory. It is expected that the astutus.sphinx extension user’s build process will move the resulting files as required by the flask application that they are developing.
-
class
astutus.sphinx.post_process.
FilePostProcessor
(input_path: str, docname: str, dyn_link_list: List[Dict], dyn_base: str, extra_head_material: str, default_template_prefix: str)¶ Bases:
object
Convert a Sphinx generated *.html file into a Jinja2 template for use with Flask.
Any post-processing directives are read and implemented, and then the result is written as a reasonably-well indented Jinja2 template for use in creating dynamic HTML pages.
The key directive to allow dynamic pages is .. astutus_dyn_include::, which allows variable-driven content generation templates created by the web site developer to be placed into the Read-the-Docs styled page.
Other directives are used to fix up navigation to dynamic pages using the vertical side bar menu generated from the toc_tree directive styled usin the Read-the-Docs theme, as well as the bread crumb navigation at the top of the page.
Methods
__init__
(input_path, docname, dyn_link_list, …)Initialize self.
Applies line oriented replacements, but does not handle table-of-contents modifications.
execute_and_write
(output_basepath)Process the Sphinx generated html file to produced a styled Jinja template
fix_navigation_hrefs
(input_html_lines)Fix up hrefs used in table of contents.
parse_li_a_href_link_line
(original_li_line)Takes a line containing a <li><a href=”…”>link_text</a></li> and parses it.
set_destination_filename
(relative_file_path)Set the destination relative filepath based on the provided input.
strip_post_processing_markup
(input_html_lines)Remove any post processing markup.
Take a list item wrapped anchor and returns lines that implement with a Jinja2 loop around it.
write_template
(output_basepath, html_text)Write the processed template to a location relative to the output base path.
-
apply_line_oriented_replacements
(input_html_lines: List[str]) → List[str]¶ Applies line oriented replacements, but does not handle table-of-contents modifications.
- Line oriented replacements include:
Remove HTML navigation features not supported for dynamic pages.
Fixing up general links as needed to work with the Flask application.
Table of contents fix-ups are handled in a separate method.
-
execute_and_write
(output_basepath: str) → None¶ Process the Sphinx generated html file to produced a styled Jinja template
The phases of the processing are:
Read whole-file related post processing directives from the HTML text.
Process the file line-by-line to make appropriate and necessary modifications.
Write the resulting processed lines out as Jinja2 template file.
Fix up hrefs used in table of contents.
The original hrefs do not necessarily have the right nesting for routes used in the Flask application. They also may need to be converted to elements that represent variable parts of the route, such as used with RESTful web applications. The variable parts of the route are identified by angle brackets similar to that used in Flask routing in the replacement dynamic links. These are expanded into Jinja2 variables and loops.
-
parse_li_a_href_link_line
(original_li_line: str) → Tuple[str, List[str], str]¶ Takes a line containing a <li><a href=”…”>link_text</a></li> and parses it.
- Returns
li_template, replacements_tags, link_replacement_text
-
set_destination_filename
(relative_file_path: str) → None¶ Set the destination relative filepath based on the provided input.
The destination relative filepat may be specified by the astutus_dyn_destination directive.
If no directive is provided, the system uses a reasonable default destination based on the docname of the file.
-
strip_post_processing_markup
(input_html_lines: List[str]) → List[str]¶ Remove any post processing markup. This markup should not be in the template.
-
wrap_in_jinja2_loop
(list_item_line_with_angled_tags: str, tags: List[str], link_text: str) → List[str]¶ Take a list item wrapped anchor and returns lines that implement with a Jinja2 loop around it.
The Flask application will provide data when rendering the template to provide a menu with a dynamic number of entries.
-
write_template
(output_basepath: str, html_text: str) → None¶ Write the processed template to a location relative to the output base path.
The actual location is derived from the output base path combined with a file-specific relative filepath.
-
For something that looks like a path, extract tags indicated by angle brackets, such as <idx>.
-
astutus.sphinx.post_process.
handle_build_finished
(app: sphinx.application.Sphinx, exception) → None¶ Post-process all generated HTML files that will be used as styled Jinja2 templates.
This method is triggered by the ‘build-finished’ event. It connects the Sphinx application to the post processing class astutus.sphinx.post_process.FilePostProcessor.
At this time, the source styled *.html are found by examining the contents within the directory identified by the astutus_dyn_pages_dir configuration variable.
The files are placed in a location identified by the astutus_dyn_styled_templates_path configuration variable.
-
astutus.sphinx.post_process.
indented_html_text_from_html_lines
(html_lines: List[str]) → str¶ Attempts to indent html in a somewhat meaningful fashion.
Needs some semi-manual patch up to take care of HTML comments.
-
astutus.sphinx.post_process.
log_as_info
(msg: str) → None¶ Log at the information for this module in a distinct color for development and troubleshooting.