Newer
Older
from mantiddoc.directives.base import AlgorithmBaseDirective
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]+)\s(version ([0-9])+)?)\s*instead.")
# Maximum height in pixels a screenshot image
# Any higher than this an an obvious gap starts to appear between the "Properties" header
# and the rest
SCREENSHOT_MAX_HEIGHT = 250
#--------------------------------------------------------------------------
class AlgorithmDirective(AlgorithmBaseDirective):
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
"""
Called by Sphinx when the ..algorithm:: directive is encountered
"""
picture = self._create_screenshot()
self._insert_screenshot_link(picture)
self._insert_toc()
self._insert_deprecation_warning()
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 outputs a reference ".. _algm-AlgorithmName: instead
It then outputs a title for the page
from mantid.api import AlgorithmFactory
alg_name = self.algorithm_name()
version = self.algorithm_version()
# page reference must come directly before the title if it wants
# to be referenced without defining the link text. Here we put the
# specific version one first so that it always must be referenced
# using the full link text ":ref`LinkText <algm-AlgorithmName-vX>`:"
self.add_rst(".. _algm-%s-v%d:\n\n" % (alg_name, version))
if AlgorithmFactory.highestVersion(alg_name) == version:
self.add_rst(".. _algm-%s:\n\n" % alg_name)
# title
title = "%s v%d" % (alg_name, version)
self.add_rst(self.make_header(title, True))
self.add_rst(u"\n.. index:: %s-v%d\n\n" % (alg_name, version))
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
screenshot: A mantiddoc.tools.Screenshot object
"""
try:
screenshots_dir = self._screenshot_directory()
except RuntimeError:
return None
# Generate image
from mantiddoc.tools.screenshot import algorithm_screenshot
if not os.path.exists(screenshots_dir):
os.makedirs(screenshots_dir)
try:
picture = algorithm_screenshot(self.algorithm_name(), screenshots_dir, version=self.algorithm_version())
except RuntimeError, exc:
env = self.state.document.settings.env
env.warn(env.docname, "Unable to generate screenshot for '%s' - %s" % (self.algorithm_name(), str(exc)))
picture = None
return picture
def _insert_screenshot_link(self, picture):
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:
picture (Screenshot): A Screenshot object
"""
env = self.state.document.settings.env
format_str = ".. figure:: %s\n"\
" :class: screenshot\n"\
" :width: %dpx\n"\
" :align: right\n\n"\
" %s\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.
if picture:
screenshots_dir, filename = os.path.split(picture.imgpath)
# Find the width of the image
width, height = picture.width, picture.height
if height > SCREENSHOT_MAX_HEIGHT:
aspect_ratio = float(width)/height
width = int(SCREENSHOT_MAX_HEIGHT*aspect_ratio)
# relative path to image
rel_path = os.path.relpath(screenshots_dir, env.srcdir)
# 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
else:
# use stock not found image
path = "/images/ImageNotFound.png"
caption = "**" + self.algorithm_name() + "** dialog."
self.add_rst(format_str % (path, width, 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()) == 4:
link_text = match.group(1)
alg_name = match.group(2)
version = match.group(4)
link = "algm-%s%s"
if version is not None:
link = link % (alg_name, "-v" + str(version))
else:
link = link % (alg_name, "")
replacement = "Use :ref:`%s <%s>` instead." % (link_text, link)
msg = DEPRECATE_USE_ALG_RE.sub(replacement, msg)
# endif
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
"""
from mantid.api import AlgorithmFactory
all_algs = AlgorithmFactory.getRegisteredAlgorithms(True)
for name, versions in all_algs.iteritems():
redirect_pagename = "algorithms/%s" % name
versions.sort()
highest_version = versions[-1]
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)