Newer
Older
from docutils import nodes
from sphinx.locale import _
from sphinx.util.compat import make_admonition
import os
REDIRECT_TEMPLATE = "redirect.html"
DEPRECATE_USE_ALG_RE = re.compile(r'Use\s([A-Z][a-zA-Z0-9]+)\sinstead')
#--------------------------------------------------------------------------
class AlgorithmDirective(BaseDirective):
"""
Inserts details of an algorithm by querying Mantid
Adds:
- A referenceable link for use with Sphinx ":ref:`` tags". If this is
the highest version of the algorithm being processed then a both
a versioned link is created and a non-versioned link
- A title
- A screenshot of the algorithm
- Table of contents
If the algorithms is deprecated then a warning is inserted.
It requires a SCREENSHOTS_DIR environment variable to be set to the
directory where a screenshot should be generated. If it is not set then
a RuntimeError occurs
required_arguments, optional_arguments = 0, 0
def run(self):
"""
Called by Sphinx when the ..algorithm:: directive is encountered
"""
self._insert_reference_link()
self._insert_pagetitle()
imgpath = self._create_screenshot()
self._insert_screenshot_link(imgpath)
self._insert_toc()
self._insert_deprecation_warning()
self.commit_rst()
return []
Keep a track of the highest versions of algorithms encountered.
The algorithm name and version are retrieved from the document name.
See BaseDirective::set_algorithm_and_version()
"""
env = self.state.document.settings.env
if not hasattr(env, "algorithm"):
env.algorithms = {}
#endif
name, version = self.algorithm_name(), self.algorithm_version()
algorithms = env.algorithms
if name in algorithms:
prev_version = algorithms[name][1]
if version > prev_version:
algorithms[name][1] = version
else:
algorithms[name] = (name, version)
def _insert_reference_link(self):
Outputs a reference to the top of the algorithm's rst
of the form ".. _algm-AlgorithmName-vVersion:", so that
the page can be referenced using
:ref:`algm-AlgorithmName-version`. If this is the highest
version then it also outputs a reference ".. _algm-AlgorithmName:
from mantid.api import AlgorithmFactory
alg_name = self.algorithm_name()
version = self.algorithm_version()
self.add_rst(".. _algm-%s-v%d:\n" % (alg_name, version))
if AlgorithmFactory.highestVersion(alg_name) == version:
self.add_rst(".. _algm-%s:\n" % alg_name)
Outputs a title for the page
"""
title = "%s v%d" % (self.algorithm_name(), self.algorithm_version())
self.add_rst(self.make_header(title, True))
def _insert_toc(self):
"""
Outputs a title for the page
"""
self.add_rst(".. contents:: Table of Contents\n :local:\n")
def _create_screenshot(self):
Creates a screenshot for the named algorithm in the "images/screenshots"
subdirectory.
The file will be named "algorithmname-vX_dlg.png", e.g. Rebin-v1_dlg.png
str: The full path to the created image
"""
from mantiddoc.tools.screenshot import algorithm_screenshot
env = self.state.document.settings.env
screenshots_dir = self._screenshot_directory()
if not os.path.exists(screenshots_dir):
os.makedirs(screenshots_dir)
try:
imgpath = algorithm_screenshot(self.algorithm_name(), screenshots_dir, version=self.algorithm_version())
except Exception, exc:
env.warn(env.docname, "Unable to generate screenshot for '%s' - %s" % (algorithm_name, str(exc)))
imgpath = os.path.join(screenshots_dir, "failed_dialog.png")
return imgpath
def _insert_screenshot_link(self, img_path):
Outputs an image link with a custom :class: style. The filename is
extracted from the path given and then a relative link to the
directory specified by the SCREENSHOTS_DIR environment variable from
the root source directory is formed.
Args:
img_path (str): The full path as on the filesystem to the image
"""
env = self.state.document.settings.env
format_str = ".. figure:: %s\n"\
" :class: screenshot\n\n"\
# Sphinx assumes that an absolute path is actually relative to the directory containing the
# conf.py file and a relative path is relative to the directory where the current rst file
# is located.
filename = os.path.split(img_path)[1]
cfgdir = env.srcdir
screenshots_dir = self._screenshot_directory()
rel_path = os.path.relpath(screenshots_dir, cfgdir)
# This is a href link so is expected to be in unix style
rel_path = rel_path.replace("\\","/")
# stick a "/" as the first character so Sphinx computes relative location from source directory
path = "/" + rel_path + "/" + filename
caption = "A screenshot of the **" + self.algorithm_name() + "** dialog."
self.add_rst(format_str % (path, caption))
def _screenshot_directory(self):
"""
Returns a full path where the screenshots should be generated. They are
put in a screenshots subdirectory of the main images directory in the source
tree. Sphinx then handles copying them to the final location
Arguments:
env (BuildEnvironment): Allows access to find the source directory
Returns:
str: A string containing a path to where the screenshots should be created. This will
be a filesystem path
"""
try:
return os.environ["SCREENSHOTS_DIR"]
except:
raise RuntimeError("The '.. algorithm::' directive requires a SCREENSHOTS_DIR environment variable to be set.")
def _insert_deprecation_warning(self):
"""
If the algorithm version is deprecated then construct a warning message
"""
from mantid.api import DeprecatedAlgorithmChecker
checker = DeprecatedAlgorithmChecker(self.algorithm_name(), self.algorithm_version())
msg = checker.isDeprecated()
if len(msg) == 0:
return
# Check for message to use another algorithm an insert a link
match = DEPRECATE_USE_ALG_RE.search(msg)
if match is not None and len(match.groups()) == 1:
name = match.group(0)
msg = DEPRECATE_USE_ALG_RE.sub(r"Use :ref:`algm-\1` instead.", msg)
self.add_rst(".. warning:: %s" % msg)
#------------------------------------------------------------------------------------------------------------
def html_collect_pages(app):
"""
Write out unversioned algorithm pages that redirect to the highest version of the algorithm
"""
env = app.builder.env
if not hasattr(env, "algorithms"):
return # nothing to do
template = REDIRECT_TEMPLATE
algorithms = env.algorithms
for name, highest_version in algorithms.itervalues():
redirect_pagename = "algorithms/%s" % name
target = "%s-v%d.html" % (name, highest_version)
context = {"name" : name, "target" : target}
yield (redirect_pagename, context, template)
#------------------------------------------------------------------------------------------------------------
"""
Setup the directives when the extension is activated
Args:
app: The main Sphinx application object
"""
app.add_directive('algorithm', AlgorithmDirective)
# connect event html collection to handler
app.connect("html-collect-pages", html_collect_pages)