From 36e8f20aa30e1aa8adb0caea01eee973145d5aac Mon Sep 17 00:00:00 2001 From: Jay Rainey <jawrainey@gmail.com> Date: Fri, 23 May 2014 10:18:58 +0100 Subject: [PATCH] Add working set of Sphinx extensions. Refs #9521 --- .../docs/sphinxext/mantiddoc/__init__.py | 0 .../mantiddoc/directives/__init__.py | 0 .../mantiddoc/directives/algorithm.py | 54 ++++++ .../sphinxext/mantiddoc/directives/aliases.py | 32 ++++ .../sphinxext/mantiddoc/directives/base.py | 54 ++++++ .../mantiddoc/directives/categories.py | 42 +++++ .../mantiddoc/directives/properties.py | 159 ++++++++++++++++++ .../sphinxext/mantiddoc/directives/summary.py | 32 ++++ 8 files changed, 373 insertions(+) create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/__init__.py create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/algorithm.py create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/aliases.py create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/base.py create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/properties.py create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/summary.py diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/__init__.py b/Code/Mantid/docs/sphinxext/mantiddoc/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/algorithm.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/algorithm.py new file mode 100644 index 00000000000..a2bf960c594 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/algorithm.py @@ -0,0 +1,54 @@ +from base import BaseDirective + + +class AlgorithmDirective(BaseDirective): + + """ + Adds a referenceable link for a given algorithm, a title, + and a screenshot of the algorithm to an rst file. + """ + + required_arguments, optional_arguments = 1, 0 + + def run(self): + """ + Called by Sphinx when the ..algorithm:: directive is encountered + """ + algorithm_name = str(self.arguments[0]) + + # Seperate methods for each unique piece of functionality. + reference = self._make_reference_link(algorithm_name) + title = self._make_header(algorithm_name, True) + screenshot = self._get_algorithm_screenshot(algorithm_name) + + return self._insert_rest(reference + title + screenshot) + + def _make_reference_link(self, algorithm_name): + """ + Outputs a reference to the top of the algorithm's rst file. + + Args: + algorithm_name (str): The name of the algorithm to reference. + + Returns: + str: A ReST formatted reference. + """ + return ".. _" + algorithm_name.title() + ":" + "\n" + + def _get_algorithm_screenshot(self, algorithm_name): + """ + Obtains the location of the screenshot for a given algorithm. + + Args: + algorithm_name (str): The name of the algorithm. + + Returns: + str: The location of the screenshot for the given algorithm. + """ + images_dir = self.state.document.settings.env.config["mantid_images"] + return ".. image:: " + images_dir + algorithm_name + ".png" + + +def setup(app): + app.add_config_value('mantid_images', 'mantid_images', 'env') + app.add_directive('algorithm', AlgorithmDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/aliases.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/aliases.py new file mode 100644 index 00000000000..55895f5ead3 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/aliases.py @@ -0,0 +1,32 @@ +from base import BaseDirective + + +class AliasesDirective(BaseDirective): + + """ + Obtains the aliases for a given algorithm based on it's name. + """ + + required_arguments, optional_arguments = 1, 0 + + def run(self): + """ + Called by Sphinx when the ..aliases:: directive is encountered. + """ + title = self._make_header(__name__.title()) + alias = self._get_alias(str(self.arguments[0])) + return self._insert_rest(title + alias) + + def _get_alias(self, algorithm_name): + """ + Return the alias for the named algorithm. + + Args: + algorithm_name (str): The name of the algorithm to get the alias for. + """ + alg = self._create_mantid_algorithm(algorithm_name) + return "This algorithm is also known as: " + "**" + alg.alias() + "**" + + +def setup(app): + app.add_directive('aliases', AliasesDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/base.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/base.py new file mode 100644 index 00000000000..ac76ddcfeb6 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/base.py @@ -0,0 +1,54 @@ +from docutils import statemachine +from docutils.parsers.rst import Directive + + +class BaseDirective(Directive): + + """ + Contains shared functionality for Mantid custom directives. + """ + + def _make_header(self, name, title=False): + """ + Makes a ReStructuredText title from the algorithm's name. + + Args: + algorithm_name (str): The name of the algorithm to use for the title. + title (bool): If True, line is inserted above & below algorithm name. + + Returns: + str: ReST formatted header with algorithm_name as content. + """ + line = "\n" + "-" * len(name) + "\n" + if title: + return line + name + line + else: + return name + line + + def _insert_rest(self, text): + """ + Inserts ReStructuredText into the algorithm file. + + Args: + text (str): Inserts ReStructuredText into the algorithm file. + + Returns: + list: Empty list. This is required by the inherited run method. + """ + self.state_machine.insert_input(statemachine.string2lines(text), "") + return [] + + def _create_mantid_algorithm(self, algorithm_name): + """ + Create and initializes a Mantid algorithm. + + Args: + algorithm_name (str): The name of the algorithm to use for the title. + + Returns: + algorithm: An instance of a Mantid algorithm. + """ + from mantid.api import AlgorithmManager + alg = AlgorithmManager.createUnmanaged(algorithm_name) + alg.initialize() + return alg diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py new file mode 100644 index 00000000000..c51a145b5f7 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py @@ -0,0 +1,42 @@ +from base import BaseDirective + + +class CategoriesDirective(BaseDirective): + + """ + Obtains the categories for a given algorithm based on it's name. + """ + + required_arguments, optional_arguments = 1, 0 + + def run(self): + """ + Called by Sphinx when the ..categories:: directive is encountered. + """ + title = self._make_header(__name__.title()) + categories = self._get_categories(str(self.arguments[0])) + return self._insert_rest(title + categories) + + def _get_categories(self, algorithm_name): + """ + Return the categories for the named algorithm. + + Args: + algorithm_name (str): The name of the algorithm. + """ + alg = self._create_mantid_algorithm(algorithm_name) + + # Create a list containing each category. + categories = alg.category().split("\\") + + if len(categories) >= 2: + # Add a cross reference for each catagory. + links = (":ref:`%s` | " * len(categories)) % tuple(categories) + # Remove last three characters to remove last | + return ("`Categories: <categories.html>`_ " + links)[:-3] + else: + return "`Category: <categoies.html>`_ :ref:`%s`" % (categories) + + +def setup(app): + app.add_directive('categories', CategoriesDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/properties.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/properties.py new file mode 100644 index 00000000000..64d5de49c74 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/properties.py @@ -0,0 +1,159 @@ +from base import BaseDirective + + +class PropertiesDirective(BaseDirective): + + """ + Outputs the given algorithm's properties into a ReST formatted table. + """ + # Accept one required argument and no optional arguments. + required_arguments, optional_arguments = 1, 0 + + def run(self): + """ + Called by Sphinx when the ..properties:: directive is encountered. + """ + alg_name = str(self.arguments[0]) + title = self._make_header(__name__.title()) + properties_table = self._populate_properties_table(alg_name) + return self._insert_rest(title + properties_table) + + def _populate_properties_table(self, algorithm_name): + """ + Populates the ReST table with algorithm properties. + + Args: + algorithm_name (str): The name of the algorithm. + """ + alg = self._create_mantid_algorithm(algorithm_name) + alg_properties = alg.getProperties() + + # Stores each property of the algorithm in a tuple. + properties = [] + + # Used to obtain the name for the direction property rather than an + # int. + direction_string = ["Input", "Output", "InOut", "None"] + + for prop in alg_properties: + # Append a tuple of properties to the list. + properties.append(( + str(prop.name), + str(direction_string[prop.direction]), + str(prop.type), + str(self._get_default_prop(prop)), + str(prop.documentation) + )) + + # Build and add the properties to the ReST table. + return self._build_table(properties) + + def _build_table(self, table_content): + """ + Build the ReST format + + Args: + table_content (list of tuples): Each tuple (row) container + property values for a unique property of that algorithm. + + Returns: + str: ReST formatted table containing algorithm properties. + """ + # Default values for the table headers. + header_content = ( + 'Name', 'Direction', 'Type', 'Default', 'Description') + # The width of the columns. Multiply row length by 10 to ensure small + # properties format correctly. + col_sizes = [max(len(row[i] * 10) for row in table_content) + for i in range(len(header_content))] + # Use the column widths as a means to formatting columns. + formatter = ' '.join('{:<%d}' % col for col in col_sizes) + # Add whitespace to each column. This depends on the values returned by + # col_sizes. + table_content_formatted = [ + formatter.format(*item) for item in table_content] + # Create a seperator for each column + seperator = formatter.format(*['=' * col for col in col_sizes]) + # Build the table. + header = '\n' + seperator + '\n' + formatter.format(*header_content) + '\n' + content = seperator + '\n' + \ + '\n'.join(table_content_formatted) + '\n' + seperator + # Join the header and footer. + return header + content + + def _get_default_prop(self, prop): + """ + Converts the default value of the property to a more use-friendly one. + + Args: + prop (str): The algorithm property to use. + + Returns: + str: The default value of the property. + """ + from mantid.api import IWorkspaceProperty + + # Used to obtain the name for the direction property rather than + # outputting an int. + direction_string = ["Input", "Output", "InOut", "None"] + + # Nothing to show under the default section for an output properties + # that are not workspace properties. + if (direction_string[prop.direction] == "Output") and \ + (not isinstance(prop, IWorkspaceProperty)): + default_prop = "" + elif (prop.isValid == ""): + default_prop = self._create_property_default_string(prop) + else: + default_prop = "Mandatory" + return default_prop + + def _create_property_default_string(self, prop): + """ + Converts the default value of the property to a more use-friendly one. + + Args: + prop. The property to find the default value of. + + Returns: + str: The string to add to the property table default section. + """ + + default = prop.getDefault + defaultstr = "" + + # Convert to int, then float, then any string + try: + val = int(default) + if (val >= 2147483647): + defaultstr = "Optional" + else: + defaultstr = str(val) + except: + try: + val = float(default) + if (val >= 1e+307): + defaultstr = "Optional" + else: + defaultstr = str(val) + except: + # Fall-back default for anything + defaultstr = str(default) + + # Replace the ugly default values with "Optional" + if (defaultstr == "8.9884656743115785e+307") or \ + (defaultstr == "1.7976931348623157e+308") or \ + (defaultstr == "2147483647"): + defaultstr = "Optional" + + if str(prop.type) == "boolean": + if defaultstr == "1": + defaultstr = "True" + else: + defaultstr = "False" + + return defaultstr + + +def setup(app): + app.add_directive('properties', PropertiesDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/summary.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/summary.py new file mode 100644 index 00000000000..c66fc706a06 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/summary.py @@ -0,0 +1,32 @@ +from base import BaseDirective + + +class SummaryDirective(BaseDirective): + + """ + Obtains the summary for a given algorithm based on it's name. + """ + + required_arguments, optional_arguments = 1, 0 + + def run(self): + """ + Called by Sphinx when the ..summary:: directive is encountered. + """ + title = self._make_header(__name__.title()) + summary = self._get_summary(str(self.arguments[0])) + return self._insert_rest(title + summary) + + def _get_summary(self, algorithm_name): + """ + Return the summary for the named algorithm. + + Args: + algorithm_name (str): The name of the algorithm. + """ + alg = self._create_mantid_algorithm(algorithm_name) + return alg.getWikiSummary() + + +def setup(app): + app.add_directive('summary', SummaryDirective) -- GitLab