Skip to content
Snippets Groups Projects
runsphinx.py.in 6.59 KiB
Newer Older
"""We need to run Sphinx inside MantidPlot to document the internal
   module. This script calls the sphinx entry point with the necessary
   arguments
"""
from optparse import OptionParser
import os
DOC_EXT = ".rst"

###############################################################################
# CMake-populated variables
###############################################################################
BUILDER = "@BUILDER@"
SRC_DIR = "@SPHINX_SRC_DIR@"
CONF_DIR = "@SPHINX_CONF_DIR@"
SPHINX_BUILD_DIR = "@SPHINX_BUILD_DIR@"
SCREENSHOTS_DIR = "@SCREENSHOTS_DIR@"
DIAGRAMS_DIR = "@DIAGRAMS_DIR@"
DOT_EXECUTABLE = "@DOT_EXECUTABLE@"

###############################################################################
# Main
###############################################################################

def main(sysarg):
    Execute the Sphinx build.

    Args:
      sysarg (list): A list of strings giving arguments to the script,
                     where it is assumed that the path to the script is the
                     first argument
    opts, args = parseargs(sysarg)
    if len(args) > 0:
        raise RuntimeError("Unexpected command line arguments: %s. "
                           "Use -h for help" % ' '.join(args))
    # Update sys path if we need to
    update_path(opts.mantidpath)
    # Find test files
    testpaths = find_test_files(SRC_DIR, opts.testinclude)

    # Update environment with screenshots path if necessary
    if SCREENSHOTS_DIR != "":
        os.environ["SCREENSHOTS_DIR"] = SCREENSHOTS_DIR
    if DIAGRAMS_DIR != "":
        os.environ["DIAGRAMS_DIR"] = DIAGRAMS_DIR

    if os.path.isfile(DOT_EXECUTABLE):
        os.environ["DOT_EXECUTABLE"] = DOT_EXECUTABLE

    output_dir = pathjoin(SPHINX_BUILD_DIR, BUILDER)
    doctree_dir = pathjoin(SPHINX_BUILD_DIR, "doctrees")
            "-c", CONF_DIR,
            SRC_DIR, output_dir]
    if testpaths is not None:
        if len(testpaths) > 0:
            argv.extend(testpaths)
        else:
            raise RuntimeError("No tests matched regex '%s'"
                                % opts.testinclude)
    # IPython monkey patches the RegexLexer.get_tokens_unprocessed method and
    # causes Sphinx to fall over. We need to put it back while processing
    # the documentation
    from pygments.lexer import RegexLexer
    # Reverse monkeypatch using unpatched function stored in mantid_ipython_widget
    # if it is available
    try:
        RegexLexer.get_tokens_unprocessed = RegexLexer.get_tokens_unprocessed_unpatched
    except AttributeError:
        pass
    try:
        return_value = sphinx.main(argv)
    finally:
        from IPython.qt.console import pygments_highlighter
        RegexLexer.get_tokens_unprocessed = pygments_highlighter.get_tokens_unprocessed
    sys.exit(return_value)
#-----------------------------------------------------------------------------------------------

def parseargs(arglist):
    """
    Split script arguments into options and arguments.

    Args:
      arglist: List of strings to control program
    """
    parser = OptionParser(usage="Usage: %prog [options]",
                          conflict_handler='error')
    parser.add_option("-m", "--mantidpath", dest="mantidpath",
                      help="Location of mantid package. Has no effect if run inside MantidPlot")
    parser.add_option("-R", "--tests-regex", dest="testinclude",
                      help="Regex specifying which tests to run. It is matched against the "
                      "filename when considering whether to run a test.")
    return parser.parse_args(arglist[1:]) # hack off filename

#-----------------------------------------------------------------------------------------------

def update_path(mantidpath):
    """
    If not inside MantidPlot (current check is whether we can import _qti)
    then insert given path as first directory in sys.path

    Args:
      mantidpath (str): A string giving the location of the mantid module
    """
    try:
        import _qti
        gui = True
    except ImportError:
        gui = False

    # If it's MantidPlot then we already know what our paths should be so ignore it
    if gui:
        return

    # check for directory
    if not os.path.isdir(os.path.join(mantidpath, "mantid")):
        raise ValueError("Unable to find mantid package in '%s'" % mantidpath)
    # is package valid
    if not os.path.isfile(os.path.join(mantidpath, "mantid", "__init__.py")):
        raise ValueError("Invalid mantid package. No __init__ found in '%s' %s")

    # Update sys.path
    sys.path.insert(0, mantidpath)

#-----------------------------------------------------------------------------------------------

def find_test_files(src_dir, name_re):
    """
    Find the test files that should be run based on a source directory
    and regex.

    Args:
      src_dir (str): A string giving the source directory of doc files
      name_re (str): A regex to match against a test filename. If None
                     then None is returned
    Returns:
      A list of paths to the chosen test files.
    """
    if name_re is None:
        return None
    name_re_comp = re.compile(name_re)
    testpaths = []
    for dirpath, dirnames, filenames in os.walk(src_dir):
        testfiles = find_matching_tests(filenames, name_re_comp)
        # Join each filename with the current path and extend the list
        testpaths.extend(map(lambda x: os.path.join(dirpath, x), testfiles))

    return testpaths

def find_matching_tests(filenames, name_re):
    """
    For a list of filenames, return the list that matches the given
    regex

    Args:
      filenames: A list of filenames
      name_re (re.regex): A compiled regex object
    Returns:
      A list of matching test names
    """
    testfiles = []
    for filename in filenames:
        if not filename.endswith(DOC_EXT):
            continue
        if name_re.match(filename.rstrip(DOC_EXT)):
            testfiles.append(filename)

    return testfiles

#-----------------------------------------------------------------------------------------------
def pathjoin(left, *args):
    """
    Similar to os.path.join but just uses "/" as it's populated with CMake-style paths that are
    always "/" separated, even on Windows.
    """
    return left + "/" + "/".join(args)

#-----------------------------------------------------------------------------------------------


##################################################################################

if __name__ == "__main__":