/docs/sphinxext/mantiddoc/directives/base.py

https://github.com/wdzhou/mantid · Python · 216 lines · 163 code · 18 blank · 35 comment · 14 complexity · 739a447b5c17e804ee33fa5da597daaa MD5 · raw file

  1. from docutils import statemachine
  2. from docutils.parsers.rst import Directive #pylint: disable=unused-import
  3. import re
  4. ALG_DOCNAME_RE = re.compile(r'^([A-Z][a-zA-Z0-9]+)-v([0-9][0-9]*)$')
  5. FIT_DOCNAME_RE = re.compile(r'^([A-Z][a-zA-Z0-9]+)$')
  6. #----------------------------------------------------------------------------------------
  7. def algorithm_name_and_version(docname):
  8. """
  9. Returns the name and version of an algorithm based on the name of the
  10. document supplied. The expected name of the document is "AlgorithmName-v?", which
  11. is the name of the file with the extension removed
  12. Arguments:
  13. docname (str): The name of the document as supplied by docutils. Can contain slashes to indicate a path
  14. Returns:
  15. tuple: A tuple containing two elements (name, version). In the case of a fit function the version is None.
  16. """
  17. # simple check to see if it is an algorithm or fit function
  18. is_alg = ("algorithms" in docname)
  19. is_fit = ("fitfunctions" in docname)
  20. # docname includes path, using forward slashes, from root of documentation directory
  21. docname = docname.split("/")[-1]
  22. # name for an algorithm
  23. if is_alg:
  24. match = ALG_DOCNAME_RE.match(docname)
  25. if not match or len(match.groups()) != 2:
  26. raise RuntimeError("Document filename '%s.rst' does not match the expected format: AlgorithmName-vX.rst" % docname)
  27. grps = match.groups()
  28. return (str(grps[0]), int(grps[1]))
  29. # name for a a fitfunction
  30. if is_fit:
  31. match = FIT_DOCNAME_RE.match(docname)
  32. if not match or len(match.groups()) != 1:
  33. raise RuntimeError("Document filename '%s.rst' does not match the expected format: FitFunctionName.rst" % docname)
  34. return (str(match.groups()[0]), None)
  35. # fail now
  36. raise RuntimeError("Faild to fine ame from document filename ")
  37. #----------------------------------------------------------------------------------------
  38. class BaseDirective(Directive):
  39. """
  40. Contains shared functionality for Mantid custom directives.
  41. """
  42. has_content = False
  43. final_argument_whitespace = True
  44. rst_lines = None
  45. def add_rst(self, text):
  46. """
  47. Appends given reST into a managed list. It is NOT inserted into the
  48. document until commit_rst() is called
  49. Args:
  50. text (str): reST to track
  51. """
  52. if self.rst_lines is None:
  53. self.rst_lines = []
  54. self.rst_lines.extend(statemachine.string2lines(text))
  55. def commit_rst(self):
  56. """
  57. Inserts the currently tracked rst lines into the state_machine
  58. """
  59. self.state_machine.insert_input(self.rst_lines, self.source())
  60. self.rst_lines = []
  61. def source(self):
  62. """
  63. Returns the full path to the source document
  64. """
  65. return self.state.document.settings.env.docname
  66. def make_header(self, name, pagetitle=False):
  67. """
  68. Makes a ReStructuredText title from the algorithm's name.
  69. Args:
  70. algorithm_name (str): The name of the algorithm to use for the title.
  71. pagetitle (bool): If True, line is inserted above & below algorithm name.
  72. Returns:
  73. str: ReST formatted header with algorithm_name as content.
  74. """
  75. if pagetitle:
  76. line = "\n" + "=" * (len(name) + 1) + "\n"
  77. return line + name + line
  78. else:
  79. line = "\n" + "-" * len(name) + "\n"
  80. return name + line
  81. #----------------------------------------------------------------------------------------
  82. class AlgorithmBaseDirective(BaseDirective):
  83. """
  84. Specialized base directive for an algorithm
  85. """
  86. algm_name = None
  87. algm_version = None
  88. def run(self):
  89. """
  90. The main entry point that docutils calls.
  91. It calls self.execute to do the main work. If an
  92. algorithm doesn't exist then the directive is
  93. skipped a debug message is emitted
  94. Derived classes should override execute() and insert
  95. whatever rst they require with self.add_rst()
  96. """
  97. nodes = []
  98. skip_msg = self.skip()
  99. if skip_msg != "":
  100. self.add_rst("**ERROR: %s**" % skip_msg)
  101. else:
  102. nodes = self.execute()
  103. if self.rst_lines is not None:
  104. self.commit_rst()
  105. return nodes
  106. def skip(self):
  107. """
  108. Override and return a string depending on whether the directive
  109. should be skipped. If empty then the directive should be processed
  110. otherwise the string should contain the error message
  111. The default is to skip (and warn) if the algorithm is not known.
  112. Returns:
  113. str: Return error mesage string if the directive should be skipped
  114. """
  115. from mantid.api import AlgorithmFactory, FunctionFactory
  116. name, version = self.algorithm_name(), self.algorithm_version()
  117. msg = ""
  118. if version is None: # it is a fit function
  119. if name in FunctionFactory.getFunctionNames():
  120. return ""
  121. else:
  122. msg = "No fit function '%s', skipping directive" % name
  123. else:
  124. if AlgorithmFactory.exists(name, version):
  125. return ""
  126. else:
  127. msg = "No algorithm '%s' version '%d', skipping directive" % (name, version)
  128. # warn the user
  129. if len(msg) > 0:
  130. env = self.state.document.settings.env
  131. env.app.verbose(msg)
  132. return msg
  133. def algorithm_name(self):
  134. """
  135. Returns the algorithm name as parsed from the document name
  136. """
  137. if self.algm_name is None:
  138. self._set_algorithm_name_and_version()
  139. return self.algm_name
  140. def algorithm_version(self):
  141. """
  142. Returns the algorithm version as parsed from the document name
  143. """
  144. if self.algm_version is None:
  145. self._set_algorithm_name_and_version()
  146. return self.algm_version
  147. def create_mantid_algorithm(self, algorithm_name, version):
  148. """
  149. Create and initializes a Mantid algorithm.
  150. Args:
  151. algorithm_name (str): The name of the algorithm to use for the title.
  152. version (int): Version of the algorithm to create
  153. Returns:
  154. algorithm: An instance of a Mantid algorithm.
  155. """
  156. from mantid.api import AlgorithmManager
  157. alg = AlgorithmManager.createUnmanaged(algorithm_name, version)
  158. alg.initialize()
  159. return alg
  160. def create_mantid_ifunction(self, function_name):
  161. """
  162. Create and initiializes a Mantid IFunction.
  163. Args:
  164. function_name (str): The name of the function to use.
  165. Returns:
  166. ifunction: An instance of a Mantid IFunction
  167. """
  168. from mantid.api import FunctionFactory
  169. return FunctionFactory.createFunction(function_name)
  170. def _set_algorithm_name_and_version(self):
  171. """
  172. Returns the name and version of an algorithm based on the name of the
  173. document. The expected name of the document is "AlgorithmName-v?", which
  174. is the name of the file with the extension removed
  175. """
  176. (self.algm_name, self.algm_version) = algorithm_name_and_version(self.source())