From a631b46d1473181916be7671fd5fc075ab92ee2e Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Thu, 7 May 2020 17:40:39 -0400 Subject: [PATCH] [cmake] Documentation build no longer requires triqs to be build with doc --- CMakeLists.txt | 3 + doc/CMakeLists.txt | 4 +- doc/conf.py.in | 18 +- doc/sphinxext/autorun/autorun.py | 104 +++ doc/sphinxext/autorun/pycon.py | 34 + doc/sphinxext/numpydoc/apigen.py | 427 ++++++++++ doc/sphinxext/numpydoc/docscrape.py | 497 +++++++++++ doc/sphinxext/numpydoc/docscrape_sphinx.py | 136 +++ doc/sphinxext/numpydoc/inheritance_diagram.py | 407 +++++++++ .../numpydoc/ipython_console_highlighting.py | 114 +++ doc/sphinxext/numpydoc/numpydoc.py | 116 +++ doc/sphinxext/numpydoc/plot_directive.py | 773 ++++++++++++++++++ doc/sphinxext/triqs_example/triqs_example.py | 123 +++ doc/themes/agogo/layout.html | 92 +++ doc/themes/agogo/static/agogo.css_t | 519 ++++++++++++ doc/themes/agogo/theme.conf | 20 + doc/themes/triqs/layout.html | 52 ++ doc/themes/triqs/static/cufon-yui.js | 7 + .../triqs/static/spaceman.cufonfonts.js | 8 + doc/themes/triqs/static/triqs.css | 449 ++++++++++ doc/themes/triqs/theme.conf | 4 + share/cmake/Modules/FindSphinx.cmake | 37 + 22 files changed, 3934 insertions(+), 10 deletions(-) create mode 100644 doc/sphinxext/autorun/autorun.py create mode 100644 doc/sphinxext/autorun/pycon.py create mode 100644 doc/sphinxext/numpydoc/apigen.py create mode 100644 doc/sphinxext/numpydoc/docscrape.py create mode 100644 doc/sphinxext/numpydoc/docscrape_sphinx.py create mode 100644 doc/sphinxext/numpydoc/inheritance_diagram.py create mode 100644 doc/sphinxext/numpydoc/ipython_console_highlighting.py create mode 100644 doc/sphinxext/numpydoc/numpydoc.py create mode 100644 doc/sphinxext/numpydoc/plot_directive.py create mode 100644 doc/sphinxext/triqs_example/triqs_example.py create mode 100644 doc/themes/agogo/layout.html create mode 100644 doc/themes/agogo/static/agogo.css_t create mode 100644 doc/themes/agogo/theme.conf create mode 100644 doc/themes/triqs/layout.html create mode 100644 doc/themes/triqs/static/cufon-yui.js create mode 100644 doc/themes/triqs/static/spaceman.cufonfonts.js create mode 100644 doc/themes/triqs/static/triqs.css create mode 100644 doc/themes/triqs/theme.conf create mode 100644 share/cmake/Modules/FindSphinx.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 79b8953a..8e3c9adb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,9 @@ set(APP4TRIQS_BINARY_DIR ${PROJECT_BINARY_DIR} CACHE STRING "Binary directory of # ############ # Options +# Make additional Find Modules available +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/share/cmake/Modules) + # Default to Release build type if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Type of build" FORCE) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e847803e..20906756 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -46,11 +46,13 @@ endforeach() # --------------------------------- # Top Sphinx target # --------------------------------- +find_package(Sphinx) + # Sphinx has internal caching, always run it add_custom_target(docs_sphinx ALL) add_custom_command( TARGET docs_sphinx - COMMAND PYTHONPATH=${PROJECT_BINARY_DIR}/python:$ENV{PYTHONPATH} ${TRIQS_SPHINXBUILD_EXECUTABLE} -c . -j8 -b html ${CMAKE_CURRENT_SOURCE_DIR} html + COMMAND PYTHONPATH=${PROJECT_BINARY_DIR}/python:$ENV{PYTHONPATH} ${SPHINXBUILD_EXECUTABLE} -c . -j8 -b html ${CMAKE_CURRENT_SOURCE_DIR} html ) option(Sphinx_Only "When building the documentation, skip the Python Modules and the generation of C++ Api and example outputs" OFF) diff --git a/doc/conf.py.in b/doc/conf.py.in index f870967c..a7656ea9 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -3,8 +3,8 @@ # TRIQS documentation build configuration file import sys -sys.path.insert(0, "@TRIQS_SPHINXEXT_PATH@/autorun") -sys.path.insert(0, "@TRIQS_SPHINXEXT_PATH@/numpydoc") +sys.path.insert(0, "@CMAKE_CURRENT_SOURCE_DIR@/sphinxext/autorun") +sys.path.insert(0, "@CMAKE_CURRENT_SOURCE_DIR@/sphinxext/numpydoc") extensions = ['sphinx.ext.autodoc', 'sphinx.ext.mathjax', @@ -13,9 +13,9 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx.ext.autosummary', - 'numpydoc', - 'plot_directive', - 'autorun'] + 'matplotlib.sphinxext.plot_directive', + 'autorun', + 'numpydoc'] source_suffix = '.rst' @@ -23,11 +23,11 @@ project = 'APP4TRIQS - An example triqs application' copyright = '2017-2018 N. Wentzell, O. Parcollet 2018-2019 The Simons Foundation, authors: N. Wentzell, D. Simons, H. Strand, O. Parcollet' version = '@PROJECT_VERSION@' -mathjax_path = "@TRIQS_MATHJAX_PATH@/MathJax.js?config=default" -templates_path = ['@PROJECT_SOURCE_DIR@/doc/_templates'] +mathjax_path = "https://raw.githubusercontent.com/mathjax/MathJax/2.7.8/MathJax.js" +templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_templates'] html_theme = 'triqs' -html_theme_path = ['@TRIQS_THEMES_PATH@'] +html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/themes'] html_show_sphinx = False html_context = {'header_title': 'app4triqs', 'header_subtitle': 'An example application using cpp2py and TRIQS', @@ -35,7 +35,7 @@ html_context = {'header_title': 'app4triqs', ['Documentation', 'documentation'], ['Issues', 'issues'], ['About app4triqs', 'about']]} -html_static_path = ['@PROJECT_SOURCE_DIR@/doc/_static'] +html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_static'] html_sidebars = {'index': ['sideb.html', 'searchbox.html']} htmlhelp_basename = 'APP4TRIQSdoc' diff --git a/doc/sphinxext/autorun/autorun.py b/doc/sphinxext/autorun/autorun.py new file mode 100644 index 00000000..cbd29742 --- /dev/null +++ b/doc/sphinxext/autorun/autorun.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +""" +sphinxcontirb.autorun +~~~~~~~~~~~~~~~~~~~~~~ + +Run the code and insert stdout after the code block. + + +""" +import os +from subprocess import Popen,PIPE + +from docutils import nodes +from docutils.parsers.rst import Directive +from docutils.parsers.rst import directives +from sphinx.errors import SphinxError +from pygments import highlight +from pygments.lexers import PythonLexer +from pygments.formatters import HtmlFormatter + +class RunBlockError(SphinxError): + category = 'runblock error' + +class AutoRun: + here = os.path.abspath(__file__) + pycon = os.path.join(os.path.dirname(here),'pycon.py') + config = dict( + pycon = 'python ' + pycon, + pycon_prefix_chars = 4, + pycon_show_source = False, + console = 'bash', + console_prefix_chars = 1 , + ) + @classmethod + def builder_init(cls,app): + cls.config.update(app.builder.config.autorun_languages) + + + +class RunBlock(Directive): + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = { + 'linenos': directives.flag, + } + + + def run(self): + config = AutoRun.config + language = self.arguments[0] + + if language not in config: + raise RunBlockError('Unknown language %s' % language) + + + # Get configuration values for the language + args = config[language].split() + #input_encoding = config.get(language+'_input_encoding','ascii') + input_encoding = 'utf8' + output_encoding = 'utf8' + #output_encoding = config.get(language+'_output_encoding','ascii') + prefix_chars = config.get(language+'_prefix_chars',0) + show_source = config.get(language+'_show_source',True) + + + # Build the code text + proc = Popen(args,bufsize=1,stdin=PIPE,stdout=PIPE,stderr=PIPE) + codelines = (line[prefix_chars:] for line in self.content) + code = '\n'.join(codelines).encode(input_encoding) + + # Run the code + stdout,stderr = proc.communicate(code) + + # Process output + out ='' + if stdout: + out += ''.join(stdout).decode(output_encoding) + if stderr: + out += ''.join(stderr).decode(output_encoding) + + # Get the original code with prefixes + if show_source: + code = '\n'.join(self.content) + else: + code = '' + #code_out = u'\n\n ---Output:---\n'.join((highlight(code, PythonLexer(), HtmlFormatter()),out)) + code_out = '\n\n ---Output:---\n'.join((code,out)) + + literal = nodes.literal_block(code_out,code_out) + #literal['language'] = language + literal['language'] = 'python' + literal['linenos'] = 'linenos' in self.options + return [literal] + + + +def setup(app): + app.add_directive('runblock', RunBlock) + app.connect('builder-inited',AutoRun.builder_init) + app.add_config_value('autorun_languages', AutoRun.config, 'env') + +# vim: set expandtab shiftwidth=4 softtabstop=4 : diff --git a/doc/sphinxext/autorun/pycon.py b/doc/sphinxext/autorun/pycon.py new file mode 100644 index 00000000..22ad46c8 --- /dev/null +++ b/doc/sphinxext/autorun/pycon.py @@ -0,0 +1,34 @@ +import sys +from code import InteractiveInterpreter + + +def main(): + """ + Print lines of input along with output. + """ + source_lines = (line.rstrip() for line in sys.stdin) + console = InteractiveInterpreter() + source = '' + try: + while True: + source = next(source_lines) + print('>>>', source) + more = console.runsource(source) + while more: + next_line = next(source_lines) + print('...', next_line) + source += '\n' + next_line + more = console.runsource(source) + except StopIteration: + if more: + print('... ') + more = console.runsource(source + '\n') + + + +if __name__ == '__main__': + main() + + +# vim: set expandtab shiftwidth=4 softtabstop=4 : + diff --git a/doc/sphinxext/numpydoc/apigen.py b/doc/sphinxext/numpydoc/apigen.py new file mode 100644 index 00000000..2619fbbd --- /dev/null +++ b/doc/sphinxext/numpydoc/apigen.py @@ -0,0 +1,427 @@ +"""Attempt to generate templates for module reference with Sphinx + +XXX - we exclude extension modules + +To include extension modules, first identify them as valid in the +``_uri2path`` method, then handle them in the ``_parse_module`` script. + +We get functions and classes by parsing the text of .py files. +Alternatively we could import the modules for discovery, and we'd have +to do that for extension modules. This would involve changing the +``_parse_module`` method to work via import and introspection, and +might involve changing ``discover_modules`` (which determines which +files are modules, and therefore which module URIs will be passed to +``_parse_module``). + +NOTE: this is a modified version of a script originally shipped with the +PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed +project.""" + +# Stdlib imports +import os +import re + +# Functions and classes +class ApiDocWriter: + ''' Class for automatic detection and parsing of API docs + to Sphinx-parsable reST format''' + + # only separating first two levels + rst_section_levels = ['*', '=', '-', '~', '^'] + + def __init__(self, + package_name, + rst_extension='.rst', + package_skip_patterns=None, + module_skip_patterns=None, + ): + ''' Initialize package for parsing + + Parameters + ---------- + package_name : string + Name of the top-level package. *package_name* must be the + name of an importable package + rst_extension : string, optional + Extension for reST files, default '.rst' + package_skip_patterns : None or sequence of {strings, regexps} + Sequence of strings giving URIs of packages to be excluded + Operates on the package path, starting at (including) the + first dot in the package path, after *package_name* - so, + if *package_name* is ``sphinx``, then ``sphinx.util`` will + result in ``.util`` being passed for earching by these + regexps. If is None, gives default. Default is: + ['\.tests$'] + module_skip_patterns : None or sequence + Sequence of strings giving URIs of modules to be excluded + Operates on the module name including preceding URI path, + back to the first dot after *package_name*. For example + ``sphinx.util.console`` results in the string to search of + ``.util.console`` + If is None, gives default. Default is: + ['\.setup$', '\._'] + ''' + if package_skip_patterns is None: + package_skip_patterns = ['\\.tests$'] + if module_skip_patterns is None: + module_skip_patterns = ['\\.setup$', '\\._'] + self.package_name = package_name + self.rst_extension = rst_extension + self.package_skip_patterns = package_skip_patterns + self.module_skip_patterns = module_skip_patterns + + def get_package_name(self): + return self._package_name + + def set_package_name(self, package_name): + ''' Set package_name + + >>> docwriter = ApiDocWriter('sphinx') + >>> import sphinx + >>> docwriter.root_path == sphinx.__path__[0] + True + >>> docwriter.package_name = 'docutils' + >>> import docutils + >>> docwriter.root_path == docutils.__path__[0] + True + ''' + # It's also possible to imagine caching the module parsing here + self._package_name = package_name + self.root_module = __import__(package_name) + self.root_path = self.root_module.__path__[0] + self.written_modules = None + + package_name = property(get_package_name, set_package_name, None, + 'get/set package_name') + + def _get_object_name(self, line): + ''' Get second token in line + >>> docwriter = ApiDocWriter('sphinx') + >>> docwriter._get_object_name(" def func(): ") + 'func' + >>> docwriter._get_object_name(" class Klass: ") + 'Klass' + >>> docwriter._get_object_name(" class Klass: ") + 'Klass' + ''' + name = line.split()[1].split('(')[0].strip() + # in case we have classes which are not derived from object + # ie. old style classes + return name.rstrip(':') + + def _uri2path(self, uri): + ''' Convert uri to absolute filepath + + Parameters + ---------- + uri : string + URI of python module to return path for + + Returns + ------- + path : None or string + Returns None if there is no valid path for this URI + Otherwise returns absolute file system path for URI + + Examples + -------- + >>> docwriter = ApiDocWriter('sphinx') + >>> import sphinx + >>> modpath = sphinx.__path__[0] + >>> res = docwriter._uri2path('sphinx.builder') + >>> res == os.path.join(modpath, 'builder.py') + True + >>> res = docwriter._uri2path('sphinx') + >>> res == os.path.join(modpath, '__init__.py') + True + >>> docwriter._uri2path('sphinx.does_not_exist') + + ''' + if uri == self.package_name: + return os.path.join(self.root_path, '__init__.py') + path = uri.replace('.', os.path.sep) + path = path.replace(self.package_name + os.path.sep, '') + path = os.path.join(self.root_path, path) + # XXX maybe check for extensions as well? + if os.path.exists(path + '.py'): # file + path += '.py' + elif os.path.exists(os.path.join(path, '__init__.py')): + path = os.path.join(path, '__init__.py') + else: + return None + return path + + def _path2uri(self, dirpath): + ''' Convert directory path to uri ''' + relpath = dirpath.replace(self.root_path, self.package_name) + if relpath.startswith(os.path.sep): + relpath = relpath[1:] + return relpath.replace(os.path.sep, '.') + + def _parse_module(self, uri): + ''' Parse module defined in *uri* ''' + filename = self._uri2path(uri) + if filename is None: + # nothing that we could handle here. + return ([],[]) + f = open(filename, 'rt') + functions, classes = self._parse_lines(f) + f.close() + return functions, classes + + def _parse_lines(self, linesource): + ''' Parse lines of text for functions and classes ''' + functions = [] + classes = [] + for line in linesource: + if line.startswith('def ') and line.count('('): + # exclude private stuff + name = self._get_object_name(line) + if not name.startswith('_'): + functions.append(name) + elif line.startswith('class '): + # exclude private stuff + name = self._get_object_name(line) + if not name.startswith('_'): + classes.append(name) + else: + pass + functions.sort() + classes.sort() + return functions, classes + + def generate_api_doc(self, uri): + '''Make autodoc documentation template string for a module + + Parameters + ---------- + uri : string + python location of module - e.g 'sphinx.builder' + + Returns + ------- + S : string + Contents of API doc + ''' + # get the names of all classes and functions + functions, classes = self._parse_module(uri) + if not len(functions) and not len(classes): + print('WARNING: Empty -',uri) # dbg + return '' + + # Make a shorter version of the uri that omits the package name for + # titles + uri_short = re.sub(r'^%s\.' % self.package_name,'',uri) + + ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n' + + chap_title = uri_short + ad += (chap_title+'\n'+ self.rst_section_levels[1] * len(chap_title) + + '\n\n') + + # Set the chapter title to read 'module' for all modules except for the + # main packages + if '.' in uri: + title = 'Module: :mod:`' + uri_short + '`' + else: + title = ':mod:`' + uri_short + '`' + ad += title + '\n' + self.rst_section_levels[2] * len(title) + + if len(classes): + ad += '\nInheritance diagram for ``%s``:\n\n' % uri + ad += '.. inheritance-diagram:: %s \n' % uri + ad += ' :parts: 3\n' + + ad += '\n.. automodule:: ' + uri + '\n' + ad += '\n.. currentmodule:: ' + uri + '\n' + multi_class = len(classes) > 1 + multi_fx = len(functions) > 1 + if multi_class: + ad += '\n' + 'Classes' + '\n' + \ + self.rst_section_levels[2] * 7 + '\n' + elif len(classes) and multi_fx: + ad += '\n' + 'Class' + '\n' + \ + self.rst_section_levels[2] * 5 + '\n' + for c in classes: + ad += '\n:class:`' + c + '`\n' \ + + self.rst_section_levels[multi_class + 2 ] * \ + (len(c)+9) + '\n\n' + ad += '\n.. autoclass:: ' + c + '\n' + # must NOT exclude from index to keep cross-refs working + ad += ' :members:\n' \ + ' :undoc-members:\n' \ + ' :show-inheritance:\n' \ + ' :inherited-members:\n' \ + '\n' \ + ' .. automethod:: __init__\n' + if multi_fx: + ad += '\n' + 'Functions' + '\n' + \ + self.rst_section_levels[2] * 9 + '\n\n' + elif len(functions) and multi_class: + ad += '\n' + 'Function' + '\n' + \ + self.rst_section_levels[2] * 8 + '\n\n' + for f in functions: + # must NOT exclude from index to keep cross-refs working + ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n' + return ad + + def _survives_exclude(self, matchstr, match_type): + ''' Returns True if *matchstr* does not match patterns + + ``self.package_name`` removed from front of string if present + + Examples + -------- + >>> dw = ApiDocWriter('sphinx') + >>> dw._survives_exclude('sphinx.okpkg', 'package') + True + >>> dw.package_skip_patterns.append('^\\.badpkg$') + >>> dw._survives_exclude('sphinx.badpkg', 'package') + False + >>> dw._survives_exclude('sphinx.badpkg', 'module') + True + >>> dw._survives_exclude('sphinx.badmod', 'module') + True + >>> dw.module_skip_patterns.append('^\\.badmod$') + >>> dw._survives_exclude('sphinx.badmod', 'module') + False + ''' + if match_type == 'module': + patterns = self.module_skip_patterns + elif match_type == 'package': + patterns = self.package_skip_patterns + else: + raise ValueError('Cannot interpret match type "%s"' + % match_type) + # Match to URI without package name + L = len(self.package_name) + if matchstr[:L] == self.package_name: + matchstr = matchstr[L:] + for pat in patterns: + try: + pat.search + except AttributeError: + pat = re.compile(pat) + if pat.search(matchstr): + return False + return True + + def discover_modules(self): + ''' Return module sequence discovered from ``self.package_name`` + + + Parameters + ---------- + None + + Returns + ------- + mods : sequence + Sequence of module names within ``self.package_name`` + + Examples + -------- + >>> dw = ApiDocWriter('sphinx') + >>> mods = dw.discover_modules() + >>> 'sphinx.util' in mods + True + >>> dw.package_skip_patterns.append('\.util$') + >>> 'sphinx.util' in dw.discover_modules() + False + >>> + ''' + modules = [self.package_name] + # raw directory parsing + for dirpath, dirnames, filenames in os.walk(self.root_path): + # Check directory names for packages + root_uri = self._path2uri(os.path.join(self.root_path, + dirpath)) + for dirname in dirnames[:]: # copy list - we modify inplace + package_uri = '.'.join((root_uri, dirname)) + if (self._uri2path(package_uri) and + self._survives_exclude(package_uri, 'package')): + modules.append(package_uri) + else: + dirnames.remove(dirname) + # Check filenames for modules + for filename in filenames: + module_name = filename[:-3] + module_uri = '.'.join((root_uri, module_name)) + if (self._uri2path(module_uri) and + self._survives_exclude(module_uri, 'module')): + modules.append(module_uri) + return sorted(modules) + + def write_modules_api(self, modules,outdir): + # write the list + written_modules = [] + for m in modules: + api_str = self.generate_api_doc(m) + if not api_str: + continue + # write out to file + outfile = os.path.join(outdir, + m + self.rst_extension) + fileobj = open(outfile, 'wt') + fileobj.write(api_str) + fileobj.close() + written_modules.append(m) + self.written_modules = written_modules + + def write_api_docs(self, outdir): + """Generate API reST files. + + Parameters + ---------- + outdir : string + Directory name in which to store files + We create automatic filenames for each module + + Returns + ------- + None + + Notes + ----- + Sets self.written_modules to list of written modules + """ + if not os.path.exists(outdir): + os.mkdir(outdir) + # compose list of modules + modules = self.discover_modules() + self.write_modules_api(modules,outdir) + + def write_index(self, outdir, froot='gen', relative_to=None): + """Make a reST API index file from written files + + Parameters + ---------- + path : string + Filename to write index to + outdir : string + Directory to which to write generated index file + froot : string, optional + root (filename without extension) of filename to write to + Defaults to 'gen'. We add ``self.rst_extension``. + relative_to : string + path to which written filenames are relative. This + component of the written file path will be removed from + outdir, in the generated index. Default is None, meaning, + leave path as it is. + """ + if self.written_modules is None: + raise ValueError('No modules written') + # Get full filename path + path = os.path.join(outdir, froot+self.rst_extension) + # Path written into index is relative to rootpath + if relative_to is not None: + relpath = outdir.replace(relative_to + os.path.sep, '') + else: + relpath = outdir + idx = open(path,'wt') + w = idx.write + w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n') + w('.. toctree::\n\n') + for f in self.written_modules: + w(' %s\n' % os.path.join(relpath,f)) + idx.close() diff --git a/doc/sphinxext/numpydoc/docscrape.py b/doc/sphinxext/numpydoc/docscrape.py new file mode 100644 index 00000000..25489154 --- /dev/null +++ b/doc/sphinxext/numpydoc/docscrape.py @@ -0,0 +1,497 @@ +"""Extract reference documentation from the NumPy source tree. + +""" + +import inspect +import textwrap +import re +import pydoc +from io import StringIO +from warnings import warn +4 +class Reader: + """A line-based string reader. + + """ + def __init__(self, data): + """ + Parameters + ---------- + data : str + String with lines separated by '\n'. + + """ + if isinstance(data,list): + self._str = data + else: + self._str = data.split('\n') # store string as list of lines + + self.reset() + + def __getitem__(self, n): + return self._str[n] + + def reset(self): + self._l = 0 # current line nr + + def read(self): + if not self.eof(): + out = self[self._l] + self._l += 1 + return out + else: + return '' + + def seek_next_non_empty_line(self): + for l in self[self._l:]: + if l.strip(): + break + else: + self._l += 1 + + def eof(self): + return self._l >= len(self._str) + + def read_to_condition(self, condition_func): + start = self._l + for line in self[start:]: + if condition_func(line): + return self[start:self._l] + self._l += 1 + if self.eof(): + return self[start:self._l+1] + return [] + + def read_to_next_empty_line(self): + self.seek_next_non_empty_line() + def is_empty(line): + return not line.strip() + return self.read_to_condition(is_empty) + + def read_to_next_unindented_line(self): + def is_unindented(line): + return (line.strip() and (len(line.lstrip()) == len(line))) + return self.read_to_condition(is_unindented) + + def peek(self,n=0): + if self._l + n < len(self._str): + return self[self._l + n] + else: + return '' + + def is_empty(self): + return not ''.join(self._str).strip() + + +class NumpyDocString: + def __init__(self,docstring): + docstring = textwrap.dedent(docstring).split('\n') + + self._doc = Reader(docstring) + self._parsed_data = { + 'Signature': '', + 'Summary': [''], + 'Extended Summary': [], + 'Parameters': [], + 'Returns': [], + 'Raises': [], + 'Warns': [], + 'Other Parameters': [], + 'Attributes': [], + 'Methods': [], + 'See Also': [], + 'Notes': [], + 'Warnings': [], + 'References': '', + 'Examples': '', + 'index': {} + } + + self._parse() + + def __getitem__(self,key): + return self._parsed_data[key] + + def __setitem__(self,key,val): + if key not in self._parsed_data: + warn("Unknown section %s" % key) + else: + self._parsed_data[key] = val + + def _is_at_section(self): + self._doc.seek_next_non_empty_line() + + if self._doc.eof(): + return False + + l1 = self._doc.peek().strip() # e.g. Parameters + + if l1.startswith('.. index::'): + return True + + l2 = self._doc.peek(1).strip() # ---------- or ========== + return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1)) + + def _strip(self,doc): + i = 0 + j = 0 + for i,line in enumerate(doc): + if line.strip(): break + + for j,line in enumerate(doc[::-1]): + if line.strip(): break + + return doc[i:len(doc)-j] + + def _read_to_next_section(self): + section = self._doc.read_to_next_empty_line() + + while not self._is_at_section() and not self._doc.eof(): + if not self._doc.peek(-1).strip(): # previous line was empty + section += [''] + + section += self._doc.read_to_next_empty_line() + + return section + + def _read_sections(self): + while not self._doc.eof(): + data = self._read_to_next_section() + name = data[0].strip() + + if name.startswith('..'): # index section + yield name, data[1:] + elif len(data) < 2: + yield StopIteration + else: + yield name, self._strip(data[2:]) + + def _parse_param_list(self,content): + r = Reader(content) + params = [] + while not r.eof(): + header = r.read().strip() + if ' : ' in header: + arg_name, arg_type = header.split(' : ')[:2] + else: + arg_name, arg_type = header, '' + + desc = r.read_to_next_unindented_line() + desc = dedent_lines(desc) + + params.append((arg_name,arg_type,desc)) + + return params + + + _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" + r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) + def _parse_see_also(self, content): + """ + func_name : Descriptive text + continued text + another_func_name : Descriptive text + func_name1, func_name2, :meth:`func_name`, func_name3 + + """ + items = [] + + def parse_item_name(text): + """Match ':role:`name`' or 'name'""" + m = self._name_rgx.match(text) + if m: + g = m.groups() + if g[1] is None: + return g[3], None + else: + return g[2], g[1] + raise ValueError("%s is not a item name" % text) + + def push_item(name, rest): + if not name: + return + name, role = parse_item_name(name) + items.append((name, list(rest), role)) + del rest[:] + + current_func = None + rest = [] + + for line in content: + if not line.strip(): continue + + m = self._name_rgx.match(line) + if m and line[m.end():].strip().startswith(':'): + push_item(current_func, rest) + current_func, line = line[:m.end()], line[m.end():] + rest = [line.split(':', 1)[1].strip()] + if not rest[0]: + rest = [] + elif not line.startswith(' '): + push_item(current_func, rest) + current_func = None + if ',' in line: + for func in line.split(','): + push_item(func, []) + elif line.strip(): + current_func = line + elif current_func is not None: + rest.append(line.strip()) + push_item(current_func, rest) + return items + + def _parse_index(self, section, content): + """ + .. index: default + :refguide: something, else, and more + + """ + def strip_each_in(lst): + return [s.strip() for s in lst] + + out = {} + section = section.split('::') + if len(section) > 1: + out['default'] = strip_each_in(section[1].split(','))[0] + for line in content: + line = line.split(':') + if len(line) > 2: + out[line[1]] = strip_each_in(line[2].split(',')) + return out + + def _parse_summary(self): + """Grab signature (if given) and summary""" + if self._is_at_section(): + return + + summary = self._doc.read_to_next_empty_line() + summary_str = " ".join([s.strip() for s in summary]).strip() + if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): + self['Signature'] = summary_str + if not self._is_at_section(): + self['Summary'] = self._doc.read_to_next_empty_line() + else: + self['Summary'] = summary + + if not self._is_at_section(): + self['Extended Summary'] = self._read_to_next_section() + + def _parse(self): + self._doc.reset() + self._parse_summary() + + for (section,content) in self._read_sections(): + if not section.startswith('..'): + section = ' '.join([s.capitalize() for s in section.split(' ')]) + if section in ('Parameters', 'Attributes', 'Methods', + 'Returns', 'Raises', 'Warns'): + self[section] = self._parse_param_list(content) + elif section.startswith('.. index::'): + self['index'] = self._parse_index(section, content) + elif section == 'See Also': + self['See Also'] = self._parse_see_also(content) + else: + self[section] = content + + # string conversion routines + + def _str_header(self, name, symbol='-'): + return [name, len(name)*symbol] + + def _str_indent(self, doc, indent=4): + out = [] + for line in doc: + out += [' '*indent + line] + return out + + def _str_signature(self): + if self['Signature']: + return [self['Signature'].replace('*','\*')] + [''] + else: + return [''] + + def _str_summary(self): + if self['Summary']: + return self['Summary'] + [''] + else: + return [] + + def _str_extended_summary(self): + if self['Extended Summary']: + return self['Extended Summary'] + [''] + else: + return [] + + def _str_param_list(self, name): + out = [] + if self[name]: + out += self._str_header(name) + for param,param_type,desc in self[name]: + out += ['%s : %s' % (param, param_type)] + out += self._str_indent(desc) + out += [''] + return out + + def _str_section(self, name): + out = [] + if self[name]: + out += self._str_header(name) + out += self[name] + out += [''] + return out + + def _str_see_also(self, func_role): + if not self['See Also']: return [] + out = [] + out += self._str_header("See Also") + last_had_desc = True + for func, desc, role in self['See Also']: + if role: + link = ':%s:`%s`' % (role, func) + elif func_role: + link = ':%s:`%s`' % (func_role, func) + else: + link = "`%s`_" % func + if desc or last_had_desc: + out += [''] + out += [link] + else: + out[-1] += ", %s" % link + if desc: + out += self._str_indent([' '.join(desc)]) + last_had_desc = True + else: + last_had_desc = False + out += [''] + return out + + def _str_index(self): + idx = self['index'] + out = [] + out += ['.. index:: %s' % idx.get('default','')] + for section, references in idx.items(): + if section == 'default': + continue + out += [' :%s: %s' % (section, ', '.join(references))] + return out + + def __str__(self, func_role=''): + out = [] + out += self._str_signature() + out += self._str_summary() + out += self._str_extended_summary() + for param_list in ('Parameters','Returns','Raises'): + out += self._str_param_list(param_list) + out += self._str_section('Warnings') + out += self._str_see_also(func_role) + for s in ('Notes','References','Examples'): + out += self._str_section(s) + out += self._str_index() + return '\n'.join(out) + + +def indent(str,indent=4): + indent_str = ' '*indent + if str is None: + return indent_str + lines = str.split('\n') + return '\n'.join(indent_str + l for l in lines) + +def dedent_lines(lines): + """Deindent a list of lines maximally""" + return textwrap.dedent("\n".join(lines)).split("\n") + +def header(text, style='-'): + return text + '\n' + style*len(text) + '\n' + + +class FunctionDoc(NumpyDocString): + def __init__(self, func, role='func', doc=None): + self._f = func + self._role = role # e.g. "func" or "meth" + if doc is None: + doc = inspect.getdoc(func) or '' + try: + NumpyDocString.__init__(self, doc) + except ValueError as e: + print('*'*78) + print("ERROR: '%s' while parsing `%s`" % (e, self._f)) + print('*'*78) + #print "Docstring follows:" + #print doclines + #print '='*78 + + if not self['Signature']: + func, func_name = self.get_func() + try: + # try to read signature + argspec = inspect.getargspec(func) + argspec = inspect.formatargspec(*argspec) + argspec = argspec.replace('*','\*') + signature = '%s%s' % (func_name, argspec) + except TypeError as e: + signature = '%s()' % func_name + self['Signature'] = signature + + def get_func(self): + func_name = getattr(self._f, '__name__', self.__class__.__name__) + if inspect.isclass(self._f): + func = getattr(self._f, '__call__', self._f.__init__) + else: + func = self._f + return func, func_name + + def __str__(self): + out = '' + + func, func_name = self.get_func() + signature = self['Signature'].replace('*', '\*') + + roles = {'func': 'function', + 'meth': 'method'} + + if self._role: + if self._role not in roles: + print("Warning: invalid role %s" % self._role) + out += '.. %s:: %s\n \n\n' % (roles.get(self._role,''), + func_name) + + out += super(FunctionDoc, self).__str__(func_role=self._role) + return out + + +class ClassDoc(NumpyDocString): + def __init__(self,cls,modulename='',func_doc=FunctionDoc,doc=None): + if not inspect.isclass(cls): + raise ValueError("Initialise using a class. Got %r" % cls) + self._cls = cls + + if modulename and not modulename.endswith('.'): + modulename += '.' + self._mod = modulename + self._name = cls.__name__ + self._func_doc = func_doc + + if doc is None: + doc = pydoc.getdoc(cls) + + NumpyDocString.__init__(self, doc) + + @property + def methods(self): + return [name for name,func in inspect.getmembers(self._cls) + if not name.startswith('_') and callable(func)] + + def __str__(self): + out = '' + out += super(ClassDoc, self).__str__() + out += "\n\n" + + #for m in self.methods: + # print "Parsing `%s`" % m + # out += str(self._func_doc(getattr(self._cls,m), 'meth')) + '\n\n' + # out += '.. index::\n single: %s; %s\n\n' % (self._name, m) + + return out + + diff --git a/doc/sphinxext/numpydoc/docscrape_sphinx.py b/doc/sphinxext/numpydoc/docscrape_sphinx.py new file mode 100644 index 00000000..2660f14f --- /dev/null +++ b/doc/sphinxext/numpydoc/docscrape_sphinx.py @@ -0,0 +1,136 @@ +import re, inspect, textwrap, pydoc +from docscrape import NumpyDocString, FunctionDoc, ClassDoc + +class SphinxDocString(NumpyDocString): + # string conversion routines + def _str_header(self, name, symbol='`'): + return ['.. rubric:: ' + name, ''] + + def _str_field_list(self, name): + return [':' + name + ':'] + + def _str_indent(self, doc, indent=4): + out = [] + for line in doc: + out += [' '*indent + line] + return out + + def _str_signature(self): + return [''] + if self['Signature']: + return ['``%s``' % self['Signature']] + [''] + else: + return [''] + + def _str_summary(self): + return self['Summary'] + [''] + + def _str_extended_summary(self): + return self['Extended Summary'] + [''] + + def _str_param_list(self, name): + out = [] + if self[name]: + out += self._str_field_list(name) + out += [''] + for param,param_type,desc in self[name]: + out += self._str_indent(['**%s** : %s' % (param.strip(), + param_type)]) + out += [''] + out += self._str_indent(desc,8) + out += [''] + return out + + def _str_section(self, name): + out = [] + if self[name]: + out += self._str_header(name) + out += [''] + content = textwrap.dedent("\n".join(self[name])).split("\n") + out += content + out += [''] + return out + + def _str_see_also(self, func_role): + out = [] + if self['See Also']: + see_also = super(SphinxDocString, self)._str_see_also(func_role) + out = ['.. seealso::', ''] + out += self._str_indent(see_also[2:]) + return out + + def _str_warnings(self): + out = [] + if self['Warnings']: + out = ['.. warning::', ''] + out += self._str_indent(self['Warnings']) + return out + + def _str_index(self): + idx = self['index'] + out = [] + if len(idx) == 0: + return out + + out += ['.. index:: %s' % idx.get('default','')] + for section, references in idx.items(): + if section == 'default': + continue + elif section == 'refguide': + out += [' single: %s' % (', '.join(references))] + else: + out += [' %s: %s' % (section, ','.join(references))] + return out + + def _str_references(self): + out = [] + if self['References']: + out += self._str_header('References') + if isinstance(self['References'], str): + self['References'] = [self['References']] + out.extend(self['References']) + out += [''] + return out + + def __str__(self, indent=0, func_role="obj"): + out = [] + out += self._str_signature() + out += self._str_index() + [''] + out += self._str_summary() + out += self._str_extended_summary() + for param_list in ('Parameters', 'Attributes', 'Methods', + 'Returns','Raises'): + out += self._str_param_list(param_list) + out += self._str_warnings() + out += self._str_see_also(func_role) + out += self._str_section('Notes') + out += self._str_references() + out += self._str_section('Examples') + out = self._str_indent(out,indent) + return '\n'.join(out) + +class SphinxFunctionDoc(SphinxDocString, FunctionDoc): + pass + +class SphinxClassDoc(SphinxDocString, ClassDoc): + pass + +def get_doc_object(obj, what=None, doc=None): + if what is None: + if inspect.isclass(obj): + what = 'class' + elif inspect.ismodule(obj): + what = 'module' + elif callable(obj): + what = 'function' + else: + what = 'object' + if what == 'class': + return SphinxClassDoc(obj, '', func_doc=SphinxFunctionDoc, doc=doc) + elif what in ('function', 'method'): + return SphinxFunctionDoc(obj, '', doc=doc) + else: + if doc is None: + doc = pydoc.getdoc(obj) + return SphinxDocString(doc) + diff --git a/doc/sphinxext/numpydoc/inheritance_diagram.py b/doc/sphinxext/numpydoc/inheritance_diagram.py new file mode 100644 index 00000000..a1ba7e7e --- /dev/null +++ b/doc/sphinxext/numpydoc/inheritance_diagram.py @@ -0,0 +1,407 @@ +""" +Defines a docutils directive for inserting inheritance diagrams. + +Provide the directive with one or more classes or modules (separated +by whitespace). For modules, all of the classes in that module will +be used. + +Example:: + + Given the following classes: + + class A: pass + class B(A): pass + class C(A): pass + class D(B, C): pass + class E(B): pass + + .. inheritance-diagram: D E + + Produces a graph like the following: + + A + / \ + B C + / \ / + E D + +The graph is inserted as a PNG+image map into HTML and a PDF in +LaTeX. +""" + +import inspect +import os +import re +import subprocess +try: + from hashlib import md5 +except ImportError: + from md5 import md5 + +from docutils.nodes import Body, Element +from docutils.parsers.rst import directives +from sphinx.roles import xfileref_role + +def my_import(name): + """Module importer - taken from the python documentation. + + This function allows importing names with dots in them.""" + + mod = __import__(name) + components = name.split('.') + for comp in components[1:]: + mod = getattr(mod, comp) + return mod + +class DotException(Exception): + pass + +class InheritanceGraph: + """ + Given a list of classes, determines the set of classes that + they inherit from all the way to the root "object", and then + is able to generate a graphviz dot graph from them. + """ + def __init__(self, class_names, show_builtins=False): + """ + *class_names* is a list of child classes to show bases from. + + If *show_builtins* is True, then Python builtins will be shown + in the graph. + """ + self.class_names = class_names + self.classes = self._import_classes(class_names) + self.all_classes = self._all_classes(self.classes) + if len(self.all_classes) == 0: + raise ValueError("No classes found for inheritance diagram") + self.show_builtins = show_builtins + + py_sig_re = re.compile(r'''^([\w.]*\.)? # class names + (\w+) \s* $ # optionally arguments + ''', re.VERBOSE) + + def _import_class_or_module(self, name): + """ + Import a class using its fully-qualified *name*. + """ + try: + path, base = self.py_sig_re.match(name).groups() + except: + raise ValueError( + "Invalid class or module '%s' specified for inheritance diagram" % name) + fullname = (path or '') + base + path = (path and path.rstrip('.')) + if not path: + path = base + try: + module = __import__(path, None, None, []) + # We must do an import of the fully qualified name. Otherwise if a + # subpackage 'a.b' is requested where 'import a' does NOT provide + # 'a.b' automatically, then 'a.b' will not be found below. This + # second call will force the equivalent of 'import a.b' to happen + # after the top-level import above. + my_import(fullname) + + except ImportError: + raise ValueError( + "Could not import class or module '%s' specified for inheritance diagram" % name) + + try: + todoc = module + for comp in fullname.split('.')[1:]: + todoc = getattr(todoc, comp) + except AttributeError: + raise ValueError( + "Could not find class or module '%s' specified for inheritance diagram" % name) + + # If a class, just return it + if inspect.isclass(todoc): + return [todoc] + elif inspect.ismodule(todoc): + classes = [] + for cls in list(todoc.__dict__.values()): + if inspect.isclass(cls) and cls.__module__ == todoc.__name__: + classes.append(cls) + return classes + raise ValueError( + "'%s' does not resolve to a class or module" % name) + + def _import_classes(self, class_names): + """ + Import a list of classes. + """ + classes = [] + for name in class_names: + classes.extend(self._import_class_or_module(name)) + return classes + + def _all_classes(self, classes): + """ + Return a list of all classes that are ancestors of *classes*. + """ + all_classes = {} + + def recurse(cls): + all_classes[cls] = None + for c in cls.__bases__: + if c not in all_classes: + recurse(c) + + for cls in classes: + recurse(cls) + + return list(all_classes.keys()) + + def class_name(self, cls, parts=0): + """ + Given a class object, return a fully-qualified name. This + works for things I've tested in matplotlib so far, but may not + be completely general. + """ + module = cls.__module__ + if module == '__builtin__': + fullname = cls.__name__ + else: + fullname = "%s.%s" % (module, cls.__name__) + if parts == 0: + return fullname + name_parts = fullname.split('.') + return '.'.join(name_parts[-parts:]) + + def get_all_class_names(self): + """ + Get all of the class names involved in the graph. + """ + return [self.class_name(x) for x in self.all_classes] + + # These are the default options for graphviz + default_graph_options = { + "rankdir": "LR", + "size": '"8.0, 12.0"' + } + default_node_options = { + "shape": "box", + "fontsize": 10, + "height": 0.25, + "fontname": "Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans", + "style": '"setlinewidth(0.5)"' + } + default_edge_options = { + "arrowsize": 0.5, + "style": '"setlinewidth(0.5)"' + } + + def _format_node_options(self, options): + return ','.join(["%s=%s" % x for x in list(options.items())]) + def _format_graph_options(self, options): + return ''.join(["%s=%s;\n" % x for x in list(options.items())]) + + def generate_dot(self, fd, name, parts=0, urls={}, + graph_options={}, node_options={}, + edge_options={}): + """ + Generate a graphviz dot graph from the classes that + were passed in to __init__. + + *fd* is a Python file-like object to write to. + + *name* is the name of the graph + + *urls* is a dictionary mapping class names to http urls + + *graph_options*, *node_options*, *edge_options* are + dictionaries containing key/value pairs to pass on as graphviz + properties. + """ + g_options = self.default_graph_options.copy() + g_options.update(graph_options) + n_options = self.default_node_options.copy() + n_options.update(node_options) + e_options = self.default_edge_options.copy() + e_options.update(edge_options) + + fd.write('digraph %s {\n' % name) + fd.write(self._format_graph_options(g_options)) + + for cls in self.all_classes: + if not self.show_builtins and cls in list(__builtins__.values()): + continue + + name = self.class_name(cls, parts) + + # Write the node + this_node_options = n_options.copy() + url = urls.get(self.class_name(cls)) + if url is not None: + this_node_options['URL'] = '"%s"' % url + fd.write(' "%s" [%s];\n' % + (name, self._format_node_options(this_node_options))) + + # Write the edges + for base in cls.__bases__: + if not self.show_builtins and base in list(__builtins__.values()): + continue + + base_name = self.class_name(base, parts) + fd.write(' "%s" -> "%s" [%s];\n' % + (base_name, name, + self._format_node_options(e_options))) + fd.write('}\n') + + def run_dot(self, args, name, parts=0, urls={}, + graph_options={}, node_options={}, edge_options={}): + """ + Run graphviz 'dot' over this graph, returning whatever 'dot' + writes to stdout. + + *args* will be passed along as commandline arguments. + + *name* is the name of the graph + + *urls* is a dictionary mapping class names to http urls + + Raises DotException for any of the many os and + installation-related errors that may occur. + """ + try: + dot = subprocess.Popen(['dot'] + list(args), + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + close_fds=True) + except OSError: + raise DotException("Could not execute 'dot'. Are you sure you have 'graphviz' installed?") + except ValueError: + raise DotException("'dot' called with invalid arguments") + except: + raise DotException("Unexpected error calling 'dot'") + + self.generate_dot(dot.stdin, name, parts, urls, graph_options, + node_options, edge_options) + dot.stdin.close() + result = dot.stdout.read() + returncode = dot.wait() + if returncode != 0: + raise DotException("'dot' returned the errorcode %d" % returncode) + return result + +class inheritance_diagram(Body, Element): + """ + A docutils node to use as a placeholder for the inheritance + diagram. + """ + pass + +def inheritance_diagram_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, + state_machine): + """ + Run when the inheritance_diagram directive is first encountered. + """ + node = inheritance_diagram() + + class_names = arguments + + # Create a graph starting with the list of classes + graph = InheritanceGraph(class_names) + + # Create xref nodes for each target of the graph's image map and + # add them to the doc tree so that Sphinx can resolve the + # references to real URLs later. These nodes will eventually be + # removed from the doctree after we're done with them. + for name in graph.get_all_class_names(): + refnodes, x = xfileref_role( + 'class', ':class:`%s`' % name, name, 0, state) + node.extend(refnodes) + # Store the graph object so we can use it to generate the + # dot file later + node['graph'] = graph + # Store the original content for use as a hash + node['parts'] = options.get('parts', 0) + node['content'] = " ".join(class_names) + return [node] + +def get_graph_hash(node): + return md5(node['content'] + str(node['parts'])).hexdigest()[-10:] + +def html_output_graph(self, node): + """ + Output the graph for HTML. This will insert a PNG with clickable + image map. + """ + graph = node['graph'] + parts = node['parts'] + + graph_hash = get_graph_hash(node) + name = "inheritance%s" % graph_hash + path = '_images' + dest_path = os.path.join(setup.app.builder.outdir, path) + if not os.path.exists(dest_path): + os.makedirs(dest_path) + png_path = os.path.join(dest_path, name + ".png") + path = setup.app.builder.imgpath + + # Create a mapping from fully-qualified class names to URLs. + urls = {} + for child in node: + if child.get('refuri') is not None: + urls[child['reftitle']] = child.get('refuri') + elif child.get('refid') is not None: + urls[child['reftitle']] = '#' + child.get('refid') + + # These arguments to dot will save a PNG file to disk and write + # an HTML image map to stdout. + image_map = graph.run_dot(['-Tpng', '-o%s' % png_path, '-Tcmapx'], + name, parts, urls) + return ('%s' % + (path, name, name, image_map)) + +def latex_output_graph(self, node): + """ + Output the graph for LaTeX. This will insert a PDF. + """ + graph = node['graph'] + parts = node['parts'] + + graph_hash = get_graph_hash(node) + name = "inheritance%s" % graph_hash + dest_path = os.path.abspath(os.path.join(setup.app.builder.outdir, '_images')) + if not os.path.exists(dest_path): + os.makedirs(dest_path) + pdf_path = os.path.abspath(os.path.join(dest_path, name + ".pdf")) + + graph.run_dot(['-Tpdf', '-o%s' % pdf_path], + name, parts, graph_options={'size': '"6.0,6.0"'}) + return '\n\\includegraphics{%s}\n\n' % pdf_path + +def visit_inheritance_diagram(inner_func): + """ + This is just a wrapper around html/latex_output_graph to make it + easier to handle errors and insert warnings. + """ + def visitor(self, node): + try: + content = inner_func(self, node) + except DotException as e: + # Insert the exception as a warning in the document + warning = self.document.reporter.warning(str(e), line=node.line) + warning.parent = node + node.children = [warning] + else: + source = self.document.attributes['source'] + self.body.append(content) + node.children = [] + return visitor + +def do_nothing(self, node): + pass + +def setup(app): + setup.app = app + setup.confdir = app.confdir + + app.add_node( + inheritance_diagram, + latex=(visit_inheritance_diagram(latex_output_graph), do_nothing), + html=(visit_inheritance_diagram(html_output_graph), do_nothing)) + app.add_directive( + 'inheritance-diagram', inheritance_diagram_directive, + False, (1, 100, 0), parts = directives.nonnegative_int) diff --git a/doc/sphinxext/numpydoc/ipython_console_highlighting.py b/doc/sphinxext/numpydoc/ipython_console_highlighting.py new file mode 100644 index 00000000..217b779d --- /dev/null +++ b/doc/sphinxext/numpydoc/ipython_console_highlighting.py @@ -0,0 +1,114 @@ +"""reST directive for syntax-highlighting ipython interactive sessions. + +XXX - See what improvements can be made based on the new (as of Sept 2009) +'pycon' lexer for the python console. At the very least it will give better +highlighted tracebacks. +""" + +#----------------------------------------------------------------------------- +# Needed modules + +# Standard library +import re + +# Third party +from pygments.lexer import Lexer, do_insertions +from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, + PythonTracebackLexer) +from pygments.token import Comment, Generic + +from sphinx import highlighting + +#----------------------------------------------------------------------------- +# Global constants +line_re = re.compile('.*?\n') + +#----------------------------------------------------------------------------- +# Code begins - classes and functions + +class IPythonConsoleLexer(Lexer): + """ + For IPython console output or doctests, such as: + + .. sourcecode:: ipython + + In [1]: a = 'foo' + + In [2]: a + Out[2]: 'foo' + + In [3]: print a + foo + + In [4]: 1 / 0 + + Notes: + + - Tracebacks are not currently supported. + + - It assumes the default IPython prompts, not customized ones. + """ + + name = 'IPython console session' + aliases = ['ipython'] + mimetypes = ['text/x-ipython-console'] + input_prompt = re.compile("(In \[[0-9]+\]: )|( \.\.\.+:)") + output_prompt = re.compile("(Out\[[0-9]+\]: )|( \.\.\.+:)") + continue_prompt = re.compile(" \.\.\.+:") + tb_start = re.compile("\-+") + + def get_tokens_unprocessed(self, text): + pylexer = PythonLexer(**self.options) + tblexer = PythonTracebackLexer(**self.options) + + curcode = '' + insertions = [] + for match in line_re.finditer(text): + line = match.group() + input_prompt = self.input_prompt.match(line) + continue_prompt = self.continue_prompt.match(line.rstrip()) + output_prompt = self.output_prompt.match(line) + if line.startswith("#"): + insertions.append((len(curcode), + [(0, Comment, line)])) + elif input_prompt is not None: + insertions.append((len(curcode), + [(0, Generic.Prompt, input_prompt.group())])) + curcode += line[input_prompt.end():] + elif continue_prompt is not None: + insertions.append((len(curcode), + [(0, Generic.Prompt, continue_prompt.group())])) + curcode += line[continue_prompt.end():] + elif output_prompt is not None: + # Use the 'error' token for output. We should probably make + # our own token, but error is typicaly in a bright color like + # red, so it works fine for our output prompts. + insertions.append((len(curcode), + [(0, Generic.Error, output_prompt.group())])) + curcode += line[output_prompt.end():] + else: + if curcode: + for item in do_insertions(insertions, + pylexer.get_tokens_unprocessed(curcode)): + yield item + curcode = '' + insertions = [] + yield match.start(), Generic.Output, line + if curcode: + for item in do_insertions(insertions, + pylexer.get_tokens_unprocessed(curcode)): + yield item + + +def setup(app): + """Setup as a sphinx extension.""" + + # This is only a lexer, so adding it below to pygments appears sufficient. + # But if somebody knows that the right API usage should be to do that via + # sphinx, by all means fix it here. At least having this setup.py + # suppresses the sphinx warning we'd get without it. + pass + +#----------------------------------------------------------------------------- +# Register the extension as a valid pygments lexer +highlighting.lexers['ipython'] = IPythonConsoleLexer() diff --git a/doc/sphinxext/numpydoc/numpydoc.py b/doc/sphinxext/numpydoc/numpydoc.py new file mode 100644 index 00000000..eea482dc --- /dev/null +++ b/doc/sphinxext/numpydoc/numpydoc.py @@ -0,0 +1,116 @@ +""" +======== +numpydoc +======== + +Sphinx extension that handles docstrings in the Numpy standard format. [1] + +It will: + +- Convert Parameters etc. sections to field lists. +- Convert See Also section to a See also entry. +- Renumber references. +- Extract the signature from the docstring, if it can't be determined otherwise. + +.. [1] http://projects.scipy.org/scipy/numpy/wiki/CodingStyleGuidelines#docstring-standard + +""" + +import os, re, pydoc +from docscrape_sphinx import get_doc_object, SphinxDocString +import inspect + +def mangle_docstrings(app, what, name, obj, options, lines, + reference_offset=[0]): + if what == 'module': + # Strip top title + title_re = re.compile(r'^\s*[#*=]{4,}\n[a-z0-9 -]+\n[#*=]{4,}\s*', + re.I|re.S) + lines[:] = title_re.sub('', "\n".join(lines)).split("\n") + else: + doc = get_doc_object(obj, what, "\n".join(lines)) + lines[:] = str(doc).split("\n") + + if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \ + obj.__name__: + if hasattr(obj, '__module__'): + v = dict(full_name="%s.%s" % (obj.__module__, obj.__name__)) + else: + v = dict(full_name=obj.__name__) + lines += ['', '.. htmlonly::', ''] + lines += [' %s' % x for x in + (app.config.numpydoc_edit_link % v).split("\n")] + + # replace reference numbers so that there are no duplicates + references = [] + for l in lines: + l = l.strip() + if l.startswith('.. ['): + try: + references.append(int(l[len('.. ['):l.index(']')])) + except ValueError: + print("WARNING: invalid reference in %s docstring" % name) + + # Start renaming from the biggest number, otherwise we may + # overwrite references. + references.sort() + if references: + for i, line in enumerate(lines): + for r in references: + new_r = reference_offset[0] + r + lines[i] = lines[i].replace('[%d]_' % r, + '[%d]_' % new_r) + lines[i] = lines[i].replace('.. [%d]' % r, + '.. [%d]' % new_r) + + reference_offset[0] += len(references) + +def mangle_signature(app, what, name, obj, options, sig, retann): + # Do not try to inspect classes that don't define `__init__` + if (inspect.isclass(obj) and + 'initializes x; see ' in pydoc.getdoc(obj.__init__)): + return '', '' + + if not (callable(obj) or hasattr(obj, '__argspec_is_invalid_')): return + if not hasattr(obj, '__doc__'): return + + doc = SphinxDocString(pydoc.getdoc(obj)) + if doc['Signature']: + sig = re.sub("^[^(]*", "", doc['Signature']) + return sig, '' + +def initialize(app): + try: + app.connect('autodoc-process-signature', mangle_signature) + except: + monkeypatch_sphinx_ext_autodoc() + +def setup(app, get_doc_object_=get_doc_object): + global get_doc_object + get_doc_object = get_doc_object_ + + app.connect('autodoc-process-docstring', mangle_docstrings) + app.connect('builder-inited', initialize) + app.add_config_value('numpydoc_edit_link', None, True) + +#------------------------------------------------------------------------------ +# Monkeypatch sphinx.ext.autodoc to accept argspecless autodocs (Sphinx < 0.5) +#------------------------------------------------------------------------------ + +def monkeypatch_sphinx_ext_autodoc(): + global _original_format_signature + import sphinx.ext.autodoc + + if sphinx.ext.autodoc.format_signature is our_format_signature: + return + + print("[numpydoc] Monkeypatching sphinx.ext.autodoc ...") + _original_format_signature = sphinx.ext.autodoc.format_signature + sphinx.ext.autodoc.format_signature = our_format_signature + +def our_format_signature(what, obj): + r = mangle_signature(None, what, None, obj, None, None, None) + if r is not None: + return r[0] + else: + return _original_format_signature(what, obj) diff --git a/doc/sphinxext/numpydoc/plot_directive.py b/doc/sphinxext/numpydoc/plot_directive.py new file mode 100644 index 00000000..be03c357 --- /dev/null +++ b/doc/sphinxext/numpydoc/plot_directive.py @@ -0,0 +1,773 @@ +""" +A directive for including a matplotlib plot in a Sphinx document. + +By default, in HTML output, `plot` will include a .png file with a +link to a high-res .png and .pdf. In LaTeX output, it will include a +.pdf. + +The source code for the plot may be included in one of three ways: + + 1. **A path to a source file** as the argument to the directive:: + + .. plot:: path/to/plot.py + + When a path to a source file is given, the content of the + directive may optionally contain a caption for the plot:: + + .. plot:: path/to/plot.py + + This is the caption for the plot + + Additionally, one my specify the name of a function to call (with + no arguments) immediately after importing the module:: + + .. plot:: path/to/plot.py plot_function1 + + 2. Included as **inline content** to the directive:: + + .. plot:: + + import matplotlib.pyplot as plt + import matplotlib.image as mpimg + import numpy as np + img = mpimg.imread('_static/stinkbug.png') + imgplot = plt.imshow(img) + + 3. Using **doctest** syntax:: + + .. plot:: + A plotting example: + >>> import matplotlib.pyplot as plt + >>> plt.plot([1,2,3], [4,5,6]) + +Options +------- + +The ``plot`` directive supports the following options: + + format : {'python', 'doctest'} + Specify the format of the input + + include-source : bool + Whether to display the source code. The default can be changed + using the `plot_include_source` variable in conf.py + + encoding : str + If this source file is in a non-UTF8 or non-ASCII encoding, + the encoding must be specified using the `:encoding:` option. + The encoding will not be inferred using the ``-*- coding -*-`` + metacomment. + + context : bool + If provided, the code will be run in the context of all + previous plot directives for which the `:context:` option was + specified. This only applies to inline code plot directives, + not those run from files. + + nofigs : bool + If specified, the code block will be run, but no figures will + be inserted. This is usually useful with the ``:context:`` + option. + +Additionally, this directive supports all of the options of the +`image` directive, except for `target` (since plot will add its own +target). These include `alt`, `height`, `width`, `scale`, `align` and +`class`. + +Configuration options +--------------------- + +The plot directive has the following configuration options: + + plot_include_source + Default value for the include-source option + + plot_pre_code + Code that should be executed before each plot. + + plot_basedir + Base directory, to which ``plot::`` file names are relative + to. (If None or empty, file names are relative to the + directoly where the file containing the directive is.) + + plot_formats + File formats to generate. List of tuples or strings:: + + [(suffix, dpi), suffix, ...] + + that determine the file format and the DPI. For entries whose + DPI was omitted, sensible defaults are chosen. + + plot_html_show_formats + Whether to show links to the files in HTML. + + plot_rcparams + A dictionary containing any non-standard rcParams that should + be applied before each plot. + +""" + +import sys, os, glob, shutil, imp, warnings, io, re, textwrap, \ + traceback, exceptions + +from docutils.parsers.rst import directives +from docutils import nodes +from docutils.parsers.rst.directives.images import Image +align = Image.align +import sphinx + +sphinx_version = sphinx.__version__.split(".") +# The split is necessary for sphinx beta versions where the string is +# '6b1' +sphinx_version = tuple([int(re.split('[a-z]', x)[0]) + for x in sphinx_version[:2]]) + +try: + # Sphinx depends on either Jinja or Jinja2 + import jinja2 + def format_template(template, **kw): + return jinja2.Template(template).render(**kw) +except ImportError: + import jinja + def format_template(template, **kw): + return jinja.from_string(template, **kw) + +import matplotlib +import matplotlib.cbook as cbook +matplotlib.use('Agg') +import matplotlib.pyplot as plt +from matplotlib import _pylab_helpers + +__version__ = 2 + +#------------------------------------------------------------------------------ +# Relative pathnames +#------------------------------------------------------------------------------ + +# os.path.relpath is new in Python 2.6 +try: + from os.path import relpath +except ImportError: + # Copied from Python 2.7 + if 'posix' in sys.builtin_module_names: + def relpath(path, start=os.path.curdir): + """Return a relative version of a path""" + from os.path import sep, curdir, join, abspath, commonprefix, \ + pardir + + if not path: + raise ValueError("no path specified") + + start_list = abspath(start).split(sep) + path_list = abspath(path).split(sep) + + # Work out how much of the filepath is shared by start and path. + i = len(commonprefix([start_list, path_list])) + + rel_list = [pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return curdir + return join(*rel_list) + elif 'nt' in sys.builtin_module_names: + def relpath(path, start=os.path.curdir): + """Return a relative version of a path""" + from os.path import sep, curdir, join, abspath, commonprefix, \ + pardir, splitunc + + if not path: + raise ValueError("no path specified") + start_list = abspath(start).split(sep) + path_list = abspath(path).split(sep) + if start_list[0].lower() != path_list[0].lower(): + unc_path, rest = splitunc(path) + unc_start, rest = splitunc(start) + if bool(unc_path) ^ bool(unc_start): + raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" + % (path, start)) + else: + raise ValueError("path is on drive %s, start on drive %s" + % (path_list[0], start_list[0])) + # Work out how much of the filepath is shared by start and path. + for i in range(min(len(start_list), len(path_list))): + if start_list[i].lower() != path_list[i].lower(): + break + else: + i += 1 + + rel_list = [pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return curdir + return join(*rel_list) + else: + raise RuntimeError("Unsupported platform (no relpath available!)") + +#------------------------------------------------------------------------------ +# Registration hook +#------------------------------------------------------------------------------ + +def plot_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + return run(arguments, content, options, state_machine, state, lineno) +plot_directive.__doc__ = __doc__ + +def _option_boolean(arg): + if not arg or not arg.strip(): + # no argument given, assume used as a flag + return True + elif arg.strip().lower() in ('no', '0', 'false'): + return False + elif arg.strip().lower() in ('yes', '1', 'true'): + return True + else: + raise ValueError('"%s" unknown boolean' % arg) + +def _option_format(arg): + return directives.choice(arg, ('python', 'doctest')) + +def _option_align(arg): + return directives.choice(arg, ("top", "middle", "bottom", "left", "center", + "right")) + +def mark_plot_labels(app, document): + """ + To make plots referenceable, we need to move the reference from + the "htmlonly" (or "latexonly") node to the actual figure node + itself. + """ + for name, explicit in document.nametypes.items(): + if not explicit: + continue + labelid = document.nameids[name] + if labelid is None: + continue + node = document.ids[labelid] + if node.tagname in ('html_only', 'latex_only'): + for n in node: + if n.tagname == 'figure': + sectname = name + for c in n: + if c.tagname == 'caption': + sectname = c.astext() + break + + node['ids'].remove(labelid) + node['names'].remove(name) + n['ids'].append(labelid) + n['names'].append(name) + document.settings.env.labels[name] = \ + document.settings.env.docname, labelid, sectname + break + +def setup(app): + setup.app = app + setup.config = app.config + setup.confdir = app.confdir + + options = {'alt': directives.unchanged, + 'height': directives.length_or_unitless, + 'width': directives.length_or_percentage_or_unitless, + 'scale': directives.nonnegative_int, + 'align': _option_align, + 'class': directives.class_option, + 'include-source': _option_boolean, + 'format': _option_format, + 'context': directives.flag, + 'nofigs': directives.flag, + 'encoding': directives.encoding + } + + app.add_directive('plot', plot_directive, True, (0, 2, False), **options) + app.add_config_value('plot_pre_code', None, True) + app.add_config_value('plot_include_source', False, True) + app.add_config_value('plot_formats', ['png', 'hires.png', 'pdf'], True) + app.add_config_value('plot_basedir', None, True) + app.add_config_value('plot_html_show_formats', True, True) + app.add_config_value('plot_rcparams', {}, True) + + app.connect('doctree-read', mark_plot_labels) + +#------------------------------------------------------------------------------ +# Doctest handling +#------------------------------------------------------------------------------ + +def contains_doctest(text): + try: + # check if it's valid Python as-is + compile(text, '', 'exec') + return False + except SyntaxError: + pass + r = re.compile(r'^\s*>>>', re.M) + m = r.search(text) + return bool(m) + +def unescape_doctest(text): + """ + Extract code from a piece of text, which contains either Python code + or doctests. + + """ + if not contains_doctest(text): + return text + + code = "" + for line in text.split("\n"): + m = re.match(r'^\s*(>>>|\.\.\.) (.*)$', line) + if m: + code += m.group(2) + "\n" + elif line.strip(): + code += "# " + line.strip() + "\n" + else: + code += "\n" + return code + +def split_code_at_show(text): + """ + Split code at plt.show() + + """ + + parts = [] + is_doctest = contains_doctest(text) + + part = [] + for line in text.split("\n"): + if (not is_doctest and line.strip() == 'plt.show()') or \ + (is_doctest and line.strip() == '>>> plt.show()'): + part.append(line) + parts.append("\n".join(part)) + part = [] + else: + part.append(line) + if "\n".join(part).strip(): + parts.append("\n".join(part)) + return parts + +#------------------------------------------------------------------------------ +# Template +#------------------------------------------------------------------------------ + + +TEMPLATE = """ +{{ source_code }} + +{{ only_html }} + + {% if source_link or (html_show_formats and not multi_image) %} + ( + {%- if source_link -%} + `Source code <{{ source_link }}>`__ + {%- endif -%} + {%- if html_show_formats and not multi_image -%} + {%- for img in images -%} + {%- for fmt in img.formats -%} + {%- if source_link or not loop.first -%}, {% endif -%} + `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ + {%- endfor -%} + {%- endfor -%} + {%- endif -%} + ) + {% endif %} + + {% for img in images %} + .. figure:: {{ build_dir }}/{{ img.basename }}.png + {%- for option in options %} + {{ option }} + {% endfor %} + + {% if html_show_formats and multi_image -%} + ( + {%- for fmt in img.formats -%} + {%- if not loop.first -%}, {% endif -%} + `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ + {%- endfor -%} + ) + {%- endif -%} + + {{ caption }} + {% endfor %} + +{{ only_latex }} + + {% for img in images %} + .. image:: {{ build_dir }}/{{ img.basename }}.pdf + {% endfor %} + +""" + +exception_template = """ +.. htmlonly:: + + [`source code <%(linkdir)s/%(basename)s.py>`__] + +Exception occurred rendering plot. + +""" + +# the context of the plot for all directives specified with the +# :context: option +plot_context = dict() + +class ImageFile: + def __init__(self, basename, dirname): + self.basename = basename + self.dirname = dirname + self.formats = [] + + def filename(self, format): + return os.path.join(self.dirname, "%s.%s" % (self.basename, format)) + + def filenames(self): + return [self.filename(fmt) for fmt in self.formats] + +def out_of_date(original, derived): + """ + Returns True if derivative is out-of-date wrt original, + both of which are full file paths. + """ + return (not os.path.exists(derived) or + (os.path.exists(original) and + os.stat(derived).st_mtime < os.stat(original).st_mtime)) + +class PlotError(RuntimeError): + pass + +def run_code(code, code_path, ns=None, function_name=None): + """ + Import a Python module from a path, and run the function given by + name, if function_name is not None. + """ + + # Change the working directory to the directory of the example, so + # it can get at its data files, if any. Add its path to sys.path + # so it can import any helper modules sitting beside it. + + pwd = os.getcwd() + old_sys_path = list(sys.path) + if code_path is not None: + dirname = os.path.abspath(os.path.dirname(code_path)) + os.chdir(dirname) + sys.path.insert(0, dirname) + + # Redirect stdout + stdout = sys.stdout + sys.stdout = io.StringIO() + + # Reset sys.argv + old_sys_argv = sys.argv + sys.argv = [code_path] + + try: + try: + code = unescape_doctest(code) + if ns is None: + ns = {} + if not ns: + if setup.config.plot_pre_code is None: + exec("import numpy as np\nfrom matplotlib import pyplot as plt\n", ns) + else: + exec(setup.config.plot_pre_code, ns) + if "__main__" in code: + exec("__name__ = '__main__'", ns) + exec(code, ns) + if function_name is not None: + exec(function_name + "()", ns) + except (Exception, SystemExit) as err: + raise PlotError(traceback.format_exc()) + finally: + os.chdir(pwd) + sys.argv = old_sys_argv + sys.path[:] = old_sys_path + sys.stdout = stdout + return ns + +def clear_state(plot_rcparams): + plt.close('all') + matplotlib.rc_file_defaults() + matplotlib.rcParams.update(plot_rcparams) + +def render_figures(code, code_path, output_dir, output_base, context, + function_name, config): + """ + Run a pyplot script and save the low and high res PNGs and a PDF + in outdir. + + Save the images under *output_dir* with file names derived from + *output_base* + """ + # -- Parse format list + default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 200} + formats = [] + plot_formats = config.plot_formats + if isinstance(plot_formats, str): + plot_formats = eval(plot_formats) + for fmt in plot_formats: + if isinstance(fmt, str): + formats.append((fmt, default_dpi.get(fmt, 80))) + elif type(fmt) in (tuple, list) and len(fmt)==2: + formats.append((str(fmt[0]), int(fmt[1]))) + else: + raise PlotError('invalid image format "%r" in plot_formats' % fmt) + + # -- Try to determine if all images already exist + + code_pieces = split_code_at_show(code) + + # Look for single-figure output files first + # Look for single-figure output files first + all_exists = True + img = ImageFile(output_base, output_dir) + for format, dpi in formats: + if out_of_date(code_path, img.filename(format)): + all_exists = False + break + img.formats.append(format) + + if all_exists: + return [(code, [img])] + + # Then look for multi-figure output files + results = [] + all_exists = True + for i, code_piece in enumerate(code_pieces): + images = [] + for j in range(1000): + if len(code_pieces) > 1: + img = ImageFile('%s_%02d_%02d' % (output_base, i, j), output_dir) + else: + img = ImageFile('%s_%02d' % (output_base, j), output_dir) + for format, dpi in formats: + if out_of_date(code_path, img.filename(format)): + all_exists = False + break + img.formats.append(format) + + # assume that if we have one, we have them all + if not all_exists: + all_exists = (j > 0) + break + images.append(img) + if not all_exists: + break + results.append((code_piece, images)) + + if all_exists: + return results + + # We didn't find the files, so build them + + results = [] + if context: + ns = plot_context + else: + ns = {} + + for i, code_piece in enumerate(code_pieces): + if not context: + clear_state(config.plot_rcparams) + run_code(code_piece, code_path, ns, function_name) + + images = [] + fig_managers = _pylab_helpers.Gcf.get_all_fig_managers() + for j, figman in enumerate(fig_managers): + if len(fig_managers) == 1 and len(code_pieces) == 1: + img = ImageFile(output_base, output_dir) + elif len(code_pieces) == 1: + img = ImageFile("%s_%02d" % (output_base, j), output_dir) + else: + img = ImageFile("%s_%02d_%02d" % (output_base, i, j), + output_dir) + images.append(img) + for format, dpi in formats: + try: + figman.canvas.figure.savefig(img.filename(format), dpi=dpi) + except Exception as err: + raise PlotError(traceback.format_exc()) + img.formats.append(format) + + results.append((code_piece, images)) + + if not context: + clear_state(config.plot_rcparams) + + return results + +def run(arguments, content, options, state_machine, state, lineno): + # The user may provide a filename *or* Python code content, but not both + if arguments and content: + raise RuntimeError("plot:: directive can't have both args and content") + + document = state_machine.document + config = document.settings.env.config + nofigs = 'nofigs' in options + + options.setdefault('include-source', config.plot_include_source) + context = 'context' in options + + rst_file = document.attributes['source'] + rst_dir = os.path.dirname(rst_file) + + if len(arguments): + if not config.plot_basedir: + source_file_name = os.path.join(setup.app.builder.srcdir, + directives.uri(arguments[0])) + else: + source_file_name = os.path.join(setup.app.builder.srcdir, config.plot_basedir, + directives.uri(arguments[0])) + + # If there is content, it will be passed as a caption. + caption = '\n'.join(content) + + # If the optional function name is provided, use it + if len(arguments) == 2: + function_name = arguments[1] + else: + function_name = None + + fd = open(source_file_name, 'r') + code = fd.read() + fd.close() + output_base = os.path.basename(source_file_name) + else: + source_file_name = rst_file + code = textwrap.dedent("\n".join(map(str, content))) + counter = document.attributes.get('_plot_counter', 0) + 1 + document.attributes['_plot_counter'] = counter + base, ext = os.path.splitext(os.path.basename(source_file_name)) + output_base = '%s-%d.py' % (base, counter) + function_name = None + caption = '' + + base, source_ext = os.path.splitext(output_base) + if source_ext in ('.py', '.rst', '.txt'): + output_base = base + else: + source_ext = '' + + # ensure that LaTeX includegraphics doesn't choke in foo.bar.pdf filenames + output_base = output_base.replace('.', '-') + + # is it in doctest format? + is_doctest = contains_doctest(code) + if 'format' in options: + if options['format'] == 'python': + is_doctest = False + else: + is_doctest = True + + # determine output directory name fragment + source_rel_name = relpath(source_file_name, setup.app.srcdir) + source_rel_dir = os.path.dirname(source_rel_name) + while source_rel_dir.startswith(os.path.sep): + source_rel_dir = source_rel_dir[1:] + + # build_dir: where to place output files (temporarily) + build_dir = os.path.join(os.path.dirname(setup.app.doctreedir), + 'plot_directive', + source_rel_dir) + # get rid of .. in paths, also changes pathsep + # see note in Python docs for warning about symbolic links on Windows. + # need to compare source and dest paths at end + build_dir = os.path.normpath(build_dir) + + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + # output_dir: final location in the builder's directory + dest_dir = os.path.abspath(os.path.join(setup.app.builder.outdir, + source_rel_dir)) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) # no problem here for me, but just use built-ins + + # how to link to files from the RST file + dest_dir_link = os.path.join(relpath(setup.app.srcdir, rst_dir), + source_rel_dir).replace(os.path.sep, '/') + build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, '/') + source_link = dest_dir_link + '/' + output_base + source_ext + + # make figures + try: + results = render_figures(code, source_file_name, build_dir, output_base, + context, function_name, config) + errors = [] + except PlotError as err: + reporter = state.memo.reporter + sm = reporter.system_message( + 2, "Exception occurred in plotting %s\n from %s:\n%s" % (output_base, + source_file_name, err), + line=lineno) + results = [(code, [])] + errors = [sm] + + # Properly indent the caption + caption = '\n'.join(' ' + line.strip() + for line in caption.split('\n')) + + # generate output restructuredtext + total_lines = [] + for j, (code_piece, images) in enumerate(results): + if options['include-source']: + if is_doctest: + lines = [''] + lines += [row.rstrip() for row in code_piece.split('\n')] + else: + lines = ['.. code-block:: python', ''] + lines += [' %s' % row.rstrip() + for row in code_piece.split('\n')] + source_code = "\n".join(lines) + else: + source_code = "" + + if nofigs: + images = [] + + opts = [':%s: %s' % (key, val) for key, val in list(options.items()) + if key in ('alt', 'height', 'width', 'scale', 'align', 'class')] + + only_html = ".. only:: html" + only_latex = ".. only:: latex" + + if j == 0: + src_link = source_link + else: + src_link = None + + result = format_template( + TEMPLATE, + dest_dir=dest_dir_link, + build_dir=build_dir_link, + source_link=src_link, + multi_image=len(images) > 1, + only_html=only_html, + only_latex=only_latex, + options=opts, + images=images, + source_code=source_code, + html_show_formats=config.plot_html_show_formats, + caption=caption) + + total_lines.extend(result.split("\n")) + total_lines.extend("\n") + + if total_lines: + state_machine.insert_input(total_lines, source=source_file_name) + + # copy image files to builder's output directory, if necessary + if not os.path.exists(dest_dir): + cbook.mkdirs(dest_dir) + + for code_piece, images in results: + for img in images: + for fn in img.filenames(): + destimg = os.path.join(dest_dir, os.path.basename(fn)) + if fn != destimg: + shutil.copyfile(fn, destimg) + + # copy script (if necessary) + #if source_file_name == rst_file: + target_name = os.path.join(dest_dir, output_base + source_ext) + f = open(target_name, 'w') + f.write(unescape_doctest(code)) + f.close() + + return errors diff --git a/doc/sphinxext/triqs_example/triqs_example.py b/doc/sphinxext/triqs_example/triqs_example.py new file mode 100644 index 00000000..2c90ac4c --- /dev/null +++ b/doc/sphinxext/triqs_example/triqs_example.py @@ -0,0 +1,123 @@ +import tempfile +# -*- coding: utf-8 -*- +# seems to be executed at the level of the conf.py +# so we need to link the lib at that place... +""" +""" +import os +import codecs +from os import path +from subprocess import Popen,PIPE +from docutils import nodes +from docutils.parsers.rst import Directive +from docutils.parsers.rst import directives +from sphinx.errors import SphinxError + +class TriqsExampleError(SphinxError): + category = 'triqs_example error' + +class TriqsExampleRun: + #here = os.path.abspath(__file__) + #pycon = os.path.join(os.path.dirname(here),'pycon.py') + config = dict( + ) + @classmethod + def builder_init(cls,app): + #cls.config.update(app.builder.config.autorun_languages) + #cls.config.update(app.builder.config.autocompile_opts) + pass + +class TriqsExample(Directive): + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = { + 'linenos': directives.flag, + } + + def run(self): + document = self.state.document + filename = self.arguments[0] + if not document.settings.file_insertion_enabled: + return [document.reporter.warning('File insertion disabled', + line=self.lineno)] + env = document.settings.env + if filename.startswith('/') or filename.startswith(os.sep): + rel_fn = filename[1:] + else: + docdir = path.dirname(env.doc2path(env.docname, base=None)) + rel_fn = path.normpath(path.join(docdir, filename)) + try: + fn = path.join(env.srcdir, rel_fn) + except UnicodeDecodeError: + # the source directory is a bytestring with non-ASCII characters; + # let's try to encode the rel_fn in the file system encoding + rel_fn = rel_fn.encode(sys.getfilesystemencoding()) + fn = path.join(env.srcdir, rel_fn) + + encoding = self.options.get('encoding', env.config.source_encoding) + try: + f = codecs.open(fn, 'rU', encoding) + lines = f.readlines() + f.close() + except (IOError, OSError): + return [document.reporter.warning( + 'Include file %r not found or reading it failed' % filename, + line=self.lineno)] + except UnicodeError: + return [document.reporter.warning( + 'Encoding %r used for reading included file %r seems to ' + 'be wrong, try giving an :encoding: option' % + (encoding, filename))] + + config = TriqsExampleRun.config + + # Get configuration values for the language + input_encoding = 'utf8' #config.get(language+'_input_encoding','ascii') + output_encoding = 'utf8' #config.get(language+'_output_encoding','ascii') + show_source = True + + # Build the code text + code = ''.join(lines).strip() + filename_clean = filename.rsplit('.',1)[0] + if filename_clean.startswith('./') : filename_clean = filename_clean[2:] + #print "Running the example ....",filename_clean + #print "Root ?", env.doc2path(env.docname, base=None) + + import subprocess as S + error = True + try : + stdout ='' + #resout = S.check_output("./example_bin/doc_%s"%(filename_clean) ,stderr=S.STDOUT,shell=True) + resout = S.check_output("./%s/doc_%s"%(docdir,filename_clean) ,stderr=S.STDOUT,shell=True) + if resout : + stdout = '---------- Result is -------\n' + resout.strip() + error = False + except S.CalledProcessError as E : + stdout ='---------- RunTime error -------\n' + stdout += E.output + + # Process output + if stdout: + stdout = stdout.decode(output_encoding,'ignore') + out = ''.join(stdout).decode(output_encoding) + else: + out = '' #.join(stderr).decode(output_encoding) + + # Get the original code with prefixes + code_out = '\n'.join((code,out)) + + if error : # report on console + print(" Error in processing ") + print(code_out) + + literal = nodes.literal_block(code_out,code_out) + literal['language'] = 'c' + literal['linenos'] = 'linenos' in self.options + return [literal] + +def setup(app): + app.add_directive('triqs_example', TriqsExample) + app.connect('builder-inited',TriqsExampleRun.builder_init) + diff --git a/doc/themes/agogo/layout.html b/doc/themes/agogo/layout.html new file mode 100644 index 00000000..869d76ad --- /dev/null +++ b/doc/themes/agogo/layout.html @@ -0,0 +1,92 @@ +{# + agogo/layout.html + ~~~~~~~~~~~~~~~~~ + + Sphinx layout template for the agogo theme, originally written + by Andi Albrecht. + + :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{% extends "basic/layout.html" %} + +{% block header %} +
+
+ {%- if logo %} + + {%- endif %} + {%- block headertitle %} +

{{ shorttitle|e }}

+ {%- endblock %} +
+ HOME | + {%- for rellink in rellinks %} + {{ rellink[3] }} + {%- if not loop.last %}{{ reldelim2 }}{% endif %} + {%- endfor %} +
+
+
+{% endblock %} + +{% block content %} +
+
+
+ {%- block document %} + {{ super() }} + {%- endblock %} +
+ +
+
+
+{% endblock %} + +{% block footer %} + +{% endblock %} + +{% block relbar1 %}{% endblock %} +{% block relbar2 %}{% endblock %} diff --git a/doc/themes/agogo/static/agogo.css_t b/doc/themes/agogo/static/agogo.css_t new file mode 100644 index 00000000..5e4b0c66 --- /dev/null +++ b/doc/themes/agogo/static/agogo.css_t @@ -0,0 +1,519 @@ +/* + * agogo.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- agogo theme. + * + * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +* { + margin: 0px; + padding: 0px; +} + +body { + font-family: {{ theme_bodyfont }}; + font-size: 100%; // TRIQS + line-height: 1.0em; // TRIQS + color: black; + background-color: {{ theme_bgcolor }}; +} + + +/* Page layout */ + +div.header, div.content, div.footer { + width: {{ theme_pagewidth }}; + margin-left: auto; + margin-right: auto; +} + +div.header-wrapper { + background: {{ theme_headerbg }}; + border-bottom: 3px solid #2e3436; +} + + +/* Default body styles */ +a { + color: {{ theme_linkcolor }}; +} + +div.bodywrapper a, div.footer a { + text-decoration: none; // TRIQS +} + +div.bodywrapper a:hover, div.footer a:hover { + text-decoration: underline; // TRIQS +} + +.clearer { + clear: both; +} + +.left { + float: left; +} + +.right { + float: right; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +h1, h2, h3, h4 { + font-family: {{ theme_headerfont }}; + font-weight: normal; + color: {{ theme_headercolor2 }}; + margin-bottom: .8em; +} + +h1 { + color: {{ theme_headercolor1 }}; +} + +h2 { + padding-bottom: .5em; + border-bottom: 1px solid {{ theme_headercolor2 }}; +} + +a.headerlink { + visibility: hidden; + color: #dddddd; + padding-left: .3em; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +img { + border: 0; +} + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 2px 7px 1px 7px; + border-left: 0.2em solid black; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; + color: red; // TRIQS +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +/* Header */ + +div.header { + padding-top: 10px; + padding-bottom: 10px; +} + +div.header h1 { + font-family: {{ theme_headerfont }}; + font-weight: normal; + font-size: 180%; + letter-spacing: .08em; +} + +div.header h1 a { + color: white; +} + +div.header div.rel { + margin-top: -1em; // TRIQS +} + +div.header div.rel a { + color: {{ theme_headerlinkcolor }}; + letter-spacing: .1em; + text-transform: uppercase; +} + +p.logo { + float: right; +} + +img.logo { + border: 0; +} + + +/* Content */ +div.content-wrapper { + background-color: white; + padding-top: 20px; + padding-bottom: 20px; +} + +div.document { + width: {{ theme_documentwidth }}; + float: left; +} + +div.body { + padding-right: 2em; + text-align: {{ theme_textalign }}; +} + +div.document ul { + margin: 1.5em; + list-style-type: square; +} + +div.document dd { + margin-left: 1.2em; + margin-top: .4em; + margin-bottom: 1em; +} + +div.document .section { + margin-top: 1.7em; +} +div.document .section:first-child { + margin-top: 0px; +} + +div.document div.highlight { + line-height: 1.0em; // TRIQS + padding: 3px; + background-color: #eeeeec; + border-top: 2px solid #dddddd; + border-bottom: 2px solid #dddddd; + margin-top: .8em; + margin-bottom: .8em; +} + +div.document h2 { + margin-top: .7em; +} + +div.document p { + margin-bottom: .5em; +} + +div.document li.toctree-l1 { + margin-bottom: 0em; // TRIQS +} +div.document li.toctree-l2 { + margin-bottom: 0em; // TRIQS +} + +div.document .descname { + font-weight: bold; + color: blue; // TRIQS +} + +div.document .docutils.literal { + background-color: #eeeeec; + padding: 1px; +} + +div.document .docutils.xref.literal { + background-color: transparent; + padding: 0px; +} + +div.document blockquote { + margin: 1em; +} + +div.document ol { + margin: 1.5em; +} + + +/* Sidebar */ + +div.sidebar { + width: {{ theme_sidebarwidth }}; + float: right; + font-size: .9em; +} + +div.sidebar a, div.header a { + text-decoration: none; +} + +div.sidebar a:hover, div.header a:hover { + text-decoration: underline; +} + +div.sidebar h3 { + color: #2e3436; + text-transform: uppercase; + font-size: 130%; + letter-spacing: .1em; +} + +div.sidebar ul { + list-style-type: none; +} + +div.sidebar li.toctree-l1 a { + display: block; + padding: 1px; + border: 1px solid #dddddd; + background-color: #eeeeec; + margin-bottom: .4em; + padding-left: 3px; + color: #2e3436; +} + +div.sidebar li.toctree-l2 a { + background-color: transparent; + border: none; + margin-left: 1em; + border-bottom: 1px solid #dddddd; +} + +div.sidebar li.toctree-l3 a { + background-color: transparent; + border: none; + margin-left: 2em; + border-bottom: 1px solid #dddddd; +} + +div.sidebar li.toctree-l2:last-child a { + border-bottom: none; +} + +div.sidebar li.toctree-l1.current a { + border-right: 5px solid {{ theme_headerlinkcolor }}; +} + +div.sidebar li.toctree-l1.current li.toctree-l2 a { + border-right: none; +} + + +/* Footer */ + +div.footer-wrapper { + background: {{ theme_footerbg }}; + border-top: 4px solid #babdb6; + padding-top: 10px; + padding-bottom: 10px; + min-height: 80px; +} + +div.footer, div.footer a { + color: #888a85; +} + +div.footer .right { + text-align: right; +} + +div.footer .left { + text-transform: uppercase; +} + + +/* Styles copied from basic theme */ + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 100%; +} + +table.contentstable td { + padding: 10px 10px 10px 0; +} + +table.contentstable p.biglink { + line-height: 150%; + text-align: left; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +/* -- viewcode extension ---------------------------------------------------- */ + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family:: {{ theme_bodyfont }}; +} + +div.viewcode-block:target { + margin: -1px -3px; + padding: 0 3px; + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +/* -- added for TRIQS ------------------------------------------------------- */ + +div.warning { + margin: 1em 0 1em 0; + border: 1px solid #86989B; + background-color: lightpink; //#f7f7f7; +} + +div.note { + margin: 1em 0 1em 0; + border: 1px solid #86989B; + background-color: lightcyan; //#f7f7f7; +} + +div.note p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; + color : blue; +} + +div.highlight-python { + margin-top : 5px; + margin-bottom : 7px; + background-color: lightcyan; //#f4debf; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils head { + color : blue; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + diff --git a/doc/themes/agogo/theme.conf b/doc/themes/agogo/theme.conf new file mode 100644 index 00000000..e2108d96 --- /dev/null +++ b/doc/themes/agogo/theme.conf @@ -0,0 +1,20 @@ +[theme] +inherit = basic +stylesheet = agogo.css +pygments_style = tango + +[options] +bodyfont = "Verdana", Arial, sans-serif +headerfont = "Georgia", "Times New Roman", serif +pagewidth = 80% +documentwidth = 75% +sidebarwidth = 22.5% +bgcolor = #eeeeec +headerbg = url(bgtop.png) top left repeat-x +footerbg = url(bgfooter.png) top left repeat-x +linkcolor = #ce5c00 +headercolor1 = #204a87 +headercolor2 = #3465a4 +headerlinkcolor = #fcaf3e +textalign = justify +index = index diff --git a/doc/themes/triqs/layout.html b/doc/themes/triqs/layout.html new file mode 100644 index 00000000..0275e11a --- /dev/null +++ b/doc/themes/triqs/layout.html @@ -0,0 +1,52 @@ +{# + layout.html + ~~~~~~~~~~~ + + TRIQS layout template heavily based on the sphinxdoc theme. + + :copyright: Copyright 2013 by the TRIQS team. + :copyright: Copyright 2007-2013 by the Sphinx team. + :license: BSD, see LICENSE for details. +#} +{%- extends "basic/layout.html" %} + +{# put the sidebar before the body #} +{% block sidebar1 %}{{ sidebar() }}{% endblock %} +{% block sidebar2 %}{% endblock %} + +{% block extrahead %} + + + + +{{ super() }} +{%- if not embedded %} + +{%- endif %} +{% endblock %} + +{% block rootrellink %} +
  • Home »
  • +{% endblock %} + +{% block header %} + +{% endblock %} diff --git a/doc/themes/triqs/static/cufon-yui.js b/doc/themes/triqs/static/cufon-yui.js new file mode 100644 index 00000000..935614e1 --- /dev/null +++ b/doc/themes/triqs/static/cufon-yui.js @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2009 Simo Kinnunen. + * Licensed under the MIT license. + * + * @version 1.09i + */ +var Cufon=(function(){var m=function(){return m.replace.apply(null,arguments)};var x=m.DOM={ready:(function(){var C=false,E={loaded:1,complete:1};var B=[],D=function(){if(C){return}C=true;for(var F;F=B.shift();F()){}};if(document.addEventListener){document.addEventListener("DOMContentLoaded",D,false);window.addEventListener("pageshow",D,false)}if(!window.opera&&document.readyState){(function(){E[document.readyState]?D():setTimeout(arguments.callee,10)})()}if(document.readyState&&document.createStyleSheet){(function(){try{document.body.doScroll("left");D()}catch(F){setTimeout(arguments.callee,1)}})()}q(window,"load",D);return function(F){if(!arguments.length){D()}else{C?F():B.push(F)}}})(),root:function(){return document.documentElement||document.body}};var n=m.CSS={Size:function(C,B){this.value=parseFloat(C);this.unit=String(C).match(/[a-z%]*$/)[0]||"px";this.convert=function(D){return D/B*this.value};this.convertFrom=function(D){return D/this.value*B};this.toString=function(){return this.value+this.unit}},addClass:function(C,B){var D=C.className;C.className=D+(D&&" ")+B;return C},color:j(function(C){var B={};B.color=C.replace(/^rgba\((.*?),\s*([\d.]+)\)/,function(E,D,F){B.opacity=parseFloat(F);return"rgb("+D+")"});return B}),fontStretch:j(function(B){if(typeof B=="number"){return B}if(/%$/.test(B)){return parseFloat(B)/100}return{"ultra-condensed":0.5,"extra-condensed":0.625,condensed:0.75,"semi-condensed":0.875,"semi-expanded":1.125,expanded:1.25,"extra-expanded":1.5,"ultra-expanded":2}[B]||1}),getStyle:function(C){var B=document.defaultView;if(B&&B.getComputedStyle){return new a(B.getComputedStyle(C,null))}if(C.currentStyle){return new a(C.currentStyle)}return new a(C.style)},gradient:j(function(F){var G={id:F,type:F.match(/^-([a-z]+)-gradient\(/)[1],stops:[]},C=F.substr(F.indexOf("(")).match(/([\d.]+=)?(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)/ig);for(var E=0,B=C.length,D;E0){E=" "+E}}else{if(B400}if(I==500){I=400}for(var J in G){if(!k(G,J)){continue}J=parseInt(J,10);if(!F||JD){D=J}K.push(J)}if(ID){I=D}K.sort(function(M,L){return(E?(M>=I&&L>=I)?ML:(M<=I&&L<=I)?M>L:Mcufoncanvas{text-indent:0;}@media screen{cvml\\:shape,cvml\\:rect,cvml\\:fill,cvml\\:shadow{behavior:url(#default#VML);display:block;antialias:true;position:absolute;}cufoncanvas{position:absolute;text-align:left;}cufon{display:inline-block;position:relative;vertical-align:'+(h?"middle":"text-bottom")+";}cufon cufontext{position:absolute;left:-10000in;font-size:1px;}a cufon{cursor:pointer}}@media print{cufon cufoncanvas{display:none;}}").replace(/;/g,"!important;"));function c(i,j){return a(i,/(?:em|ex|%)$|^[a-z-]+$/i.test(j)?"1em":j)}function a(l,m){if(m==="0"){return 0}if(/px$/i.test(m)){return parseFloat(m)}var k=l.style.left,j=l.runtimeStyle.left;l.runtimeStyle.left=l.currentStyle.left;l.style.left=m.replace("%","em");var i=l.style.pixelLeft;l.style.left=k;l.runtimeStyle.left=j;return i}function f(l,k,j,n){var i="computed"+n,m=k[i];if(isNaN(m)){m=k.get(n);k[i]=m=(m=="normal")?0:~~j.convertFrom(a(l,m))}return m}var g={};function d(p){var q=p.id;if(!g[q]){var n=p.stops,o=document.createElement("cvml:fill"),i=[];o.type="gradient";o.angle=180;o.focus="0";o.method="sigma";o.color=n[0][1];for(var m=1,l=n.length-1;mO){O=K}if(I>N){N=I}if(K":{"w":232},"?":{"d":"413,-133r0,133r-192,0r0,-133r192,0xm221,-188v-13,-173,78,-281,237,-282r341,0v53,0,80,-24,80,-71v0,-47,-27,-71,-80,-71r-799,0r0,-166r817,-1v141,-1,227,93,227,236v0,149,-87,234,-227,234r-315,0v-67,-1,-99,45,-89,121r-192,0","w":1218},"@":{"d":"305,-388v0,55,25,70,85,70r436,0r0,-146r-439,0v-55,0,-82,25,-82,76xm339,-62v-218,3,-334,-116,-339,-327v-4,-168,93,-282,227,-315v106,-26,574,-16,605,-3v56,23,105,70,105,151r0,316r-579,0v-98,2,-164,-54,-164,-148v0,-106,69,-154,188,-154r444,0v-2,-97,-62,-97,-185,-100v-135,-3,-342,-4,-427,22v-86,26,-136,115,-136,231v0,166,96,250,261,250r483,0r0,77r-483,0","w":1060},"A":{"d":"754,-341v0,-61,-24,-84,-89,-84r-626,0r0,-131r667,0v135,5,215,66,215,217r0,339r-745,0v-108,1,-176,-63,-176,-171v0,-107,69,-171,176,-170r578,0xm754,-131r0,-85r-534,0v-35,0,-53,14,-53,43v0,28,18,42,53,42r534,0","w":1096},"B":{"d":"969,-278v0,176,-93,278,-267,278r-702,0r0,-778r167,0r0,222r535,0v170,-2,267,101,267,278xm794,-278v0,-81,-38,-139,-114,-139r-513,0r0,278r513,0v76,0,114,-58,114,-139","w":1097},"C":{"d":"0,-278v0,-173,94,-278,267,-278r595,0r0,139r-573,0v-76,0,-114,58,-114,139v0,81,38,139,114,139r573,0r0,139r-595,0v-173,1,-267,-105,-267,-278","w":1022},"D":{"d":"0,-278v-1,-176,93,-278,267,-278r521,0r0,-222r167,0r0,778r-688,0v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r499,0r0,-278r-499,0v-76,0,-114,58,-114,139","w":1130},"E":{"d":"176,-216v24,58,48,85,113,85r581,0r0,131r-603,0v-173,1,-267,-105,-267,-278v0,-173,94,-278,267,-278r603,0r0,131r-581,0v-65,4,-87,27,-113,84r694,0r0,125r-694,0","w":1022},"F":{"d":"105,-341v-10,-142,29,-222,167,-222r501,1r0,130r-423,0v-60,-4,-81,31,-78,91r501,-2r0,131r-501,2r0,425r-167,0r0,-425r-105,0r0,-131r105,0","w":906},"G":{"d":"0,-278v0,-173,94,-278,267,-278r770,1r0,571v3,126,-82,208,-203,208r-773,-2r0,-130r743,1v55,0,68,-33,66,-93r-603,0v-173,1,-267,-105,-267,-278xm175,-278v0,81,37,139,114,139r581,-2r0,-275r-581,-1v-76,0,-114,58,-114,139","w":1204},"H":{"d":"735,-359v1,-35,-25,-58,-58,-58r-510,0r0,417r-167,0r0,-778r167,0r0,222r537,0v116,-4,198,68,198,170r0,386r-167,0r0,-359"},"I":{"d":"167,0r-167,0r0,-556r167,0r0,556xm167,-612r-167,0r0,-133r167,0r0,133","w":334},"J":{"d":"743,-612r-167,0r0,-133r167,0r0,133xm743,40v-5,114,-100,182,-221,182r-522,0r0,-139r510,0v44,0,66,-24,66,-73r0,-566r167,0r0,596","w":916},"K":{"d":"767,-481r146,0r0,-77r-146,0r0,77xm1040,-2v25,-199,-69,-334,-263,-334r-610,1r0,-442r-167,0r0,775r167,0r0,-195r588,0v95,-4,128,100,107,195r178,0xm914,-481v0,97,-49,145,-146,145r0,-145r146,0xm767,-481v4,77,-98,149,-175,146r175,0r0,-146","w":1195},"L":{"d":"183,-299v0,80,47,132,132,132r523,0r0,167r-569,0v-174,4,-268,-107,-268,-282r0,-276r182,0r0,259","w":996},"M":{"d":"961,-556v116,-4,197,66,197,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-273,0r0,417r-167,0r0,-417r-326,0r0,417r-167,0r0,-556r961,0","w":1312},"N":{"d":"688,-556v116,-4,198,68,198,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-494,0r0,417r-167,0r0,-556r688,0","w":1057},"O":{"d":"7,-368v-3,-111,96,-207,207,-207r536,0v112,-3,207,95,207,207r0,162v3,111,-96,207,-207,207r-536,0v-110,3,-207,-97,-207,-207r0,-162xm264,-445v-45,-1,-85,40,-85,85r0,138v-1,45,40,85,85,85r428,0v45,1,85,-40,85,-85r0,-138v1,-45,-40,-85,-85,-85r-428,0","w":1104},"P":{"d":"986,-278v1,176,-93,278,-267,278r-552,0r0,222r-167,0r0,-778r719,0v171,-2,266,102,267,278xm811,-278v0,-81,-38,-139,-114,-139r-530,0r0,278r530,0v76,0,114,-58,114,-139","w":1141},"Q":{"d":"0,-278v-1,-176,93,-278,267,-278r777,2r0,776r-167,0r0,-223r-610,1v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r588,-1r0,-275r-588,-2v-77,0,-114,58,-114,139","w":1211},"R":{"d":"610,-558v134,0,213,83,197,228r-167,0v4,-51,-8,-86,-58,-86r-415,-1r0,417r-167,0r0,-556","w":950},"S":{"d":"913,-170v0,103,-65,170,-175,170r-738,0r0,-131r705,1v37,0,55,-14,55,-43v0,-28,-18,-42,-55,-42r-530,-1v-102,1,-175,-66,-175,-169v0,-101,66,-171,175,-171r708,0r0,131r-675,0v-37,0,-55,14,-55,42v0,28,18,42,55,42r530,1v102,-1,175,67,175,170","w":1039},"T":{"d":"267,-208v1,58,20,77,78,77r425,0r0,131r-504,0v-116,-3,-166,-47,-166,-167r0,-258r-100,0r0,-131r100,0r0,-222r167,0r0,222r503,0r0,131r-503,0r0,217","w":917},"U":{"d":"198,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,358v0,39,19,59,58,59r506,0r0,-417r167,0r0,556r-700,0"},"V":{"d":"167,-139r564,0r0,-417r167,0r0,556r-898,0r0,-556r167,0r0,417"},"W":{"d":"197,0v-115,4,-197,-68,-197,-170r0,-386r167,0r0,358v0,39,19,59,58,59r273,0r0,-417r167,0r0,417r326,0r0,-417r167,0r0,556r-961,0","w":1323},"X":{"d":"132,-208r646,0r0,-131r-646,0r0,131xm1,-138v-2,-70,61,-133,131,-131r0,131r-131,0xm0,-138r132,0r0,138r-132,0r0,-138xm1,-396v-2,71,61,133,131,131r0,-131r-131,0xm0,-396r132,0r0,-158r-132,0r0,158xm909,-138v2,-70,-61,-133,-131,-131r0,131r131,0xm910,-138r-132,0r0,138r132,0r0,-138xm909,-396v2,71,-61,133,-131,131r0,-131r131,0xm910,-396r-132,0r0,-158r132,0r0,158xm133,-454v-2,62,53,117,115,115r-115,0r0,-115xm133,-94v-2,-62,53,-117,115,-115r-115,0r0,115xm777,-454v2,62,-53,117,-115,115r115,0r0,-115xm778,-93v2,-62,-54,-117,-115,-115r115,0r0,115","w":1017},"Y":{"d":"754,92v53,-1,68,-31,66,-92r-622,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,336v-1,49,32,82,81,81r572,0r0,-417r167,0r0,576v3,124,-85,207,-204,207r-769,0r0,-135r740,0","w":1169},"Z":{"d":"0,-170v0,101,66,170,175,170r738,0r0,-131r-704,1v-37,0,-56,-14,-56,-43v0,-28,19,-42,56,-42r529,-1v102,1,175,-66,175,-169v0,-102,-66,-171,-175,-171r-707,-2r0,131r674,2v37,0,55,14,55,42v0,28,-18,42,-55,42r-530,1v-102,-1,-175,67,-175,170","w":1039},"[":{"d":"0,-931r306,0r0,153r-153,0r0,778r153,0r0,153r-306,0r0,-1084","w":361},"\\":{"d":"877,0r-692,-778r-185,0r681,778r196,0","w":942},"]":{"w":366},"^":{"w":406},"_":{"d":"0,61r1001,0r0,161r-1001,0r0,-161","w":1172},"`":{"d":"0,-806r94,0r112,111r-95,0","w":261},"a":{"d":"754,-341v0,-61,-24,-84,-89,-84r-626,0r0,-131r667,0v135,5,215,66,215,217r0,339r-745,0v-108,1,-176,-63,-176,-171v0,-107,69,-171,176,-170r578,0xm754,-131r0,-85r-534,0v-35,0,-53,14,-53,43v0,28,18,42,53,42r534,0","w":1096},"b":{"d":"969,-278v0,176,-93,278,-267,278r-702,0r0,-778r167,0r0,222r535,0v170,-2,267,101,267,278xm794,-278v0,-81,-38,-139,-114,-139r-513,0r0,278r513,0v76,0,114,-58,114,-139","w":1097},"c":{"d":"0,-278v0,-173,94,-278,267,-278r595,0r0,139r-573,0v-76,0,-114,58,-114,139v0,81,38,139,114,139r573,0r0,139r-595,0v-173,1,-267,-105,-267,-278","w":1022},"d":{"d":"0,-278v-1,-176,93,-278,267,-278r521,0r0,-222r167,0r0,778r-688,0v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r499,0r0,-278r-499,0v-76,0,-114,58,-114,139","w":1130},"e":{"d":"176,-216v24,58,48,85,113,85r581,0r0,131r-603,0v-173,1,-267,-105,-267,-278v0,-173,94,-278,267,-278r603,0r0,131r-581,0v-65,4,-87,27,-113,84r694,0r0,125r-694,0","w":1022},"f":{"d":"105,-341v-10,-142,29,-222,167,-222r501,1r0,130r-423,0v-60,-4,-81,31,-78,91r501,-2r0,131r-501,2r0,425r-167,0r0,-425r-105,0r0,-131r105,0","w":906},"g":{"d":"0,-278v0,-173,94,-278,267,-278r770,1r0,571v3,126,-82,208,-203,208r-773,-2r0,-130r743,1v55,0,68,-33,66,-93r-603,0v-173,1,-267,-105,-267,-278xm175,-278v0,81,37,139,114,139r581,-2r0,-275r-581,-1v-76,0,-114,58,-114,139","w":1204},"h":{"d":"735,-359v1,-35,-25,-58,-58,-58r-510,0r0,417r-167,0r0,-778r167,0r0,222r537,0v116,-4,198,68,198,170r0,386r-167,0r0,-359"},"i":{"d":"167,0r-167,0r0,-556r167,0r0,556xm167,-612r-167,0r0,-133r167,0r0,133","w":334},"j":{"d":"743,-612r-167,0r0,-133r167,0r0,133xm743,40v-5,114,-100,182,-221,182r-522,0r0,-139r510,0v44,0,66,-24,66,-73r0,-566r167,0r0,596","w":916},"k":{"d":"767,-481r146,0r0,-77r-146,0r0,77xm1040,-2v25,-199,-69,-334,-263,-334r-610,1r0,-442r-167,0r0,775r167,0r0,-195r588,0v95,-4,128,100,107,195r178,0xm914,-481v0,97,-49,145,-146,145r0,-145r146,0xm767,-481v4,77,-98,149,-175,146r175,0r0,-146","w":1195},"l":{"d":"183,-299v0,80,47,132,132,132r523,0r0,167r-569,0v-174,4,-268,-107,-268,-282r0,-276r182,0r0,259","w":996},"m":{"d":"961,-556v116,-4,197,66,197,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-273,0r0,417r-167,0r0,-417r-326,0r0,417r-167,0r0,-556r961,0","w":1312},"n":{"d":"688,-556v116,-4,198,68,198,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-494,0r0,417r-167,0r0,-556r688,0","w":1057},"o":{"d":"7,-368v-3,-111,96,-207,207,-207r536,0v112,-3,207,95,207,207r0,162v3,111,-96,207,-207,207r-536,0v-110,3,-207,-97,-207,-207r0,-162xm264,-445v-45,-1,-85,40,-85,85r0,138v-1,45,40,85,85,85r428,0v45,1,85,-40,85,-85r0,-138v1,-45,-40,-85,-85,-85r-428,0","w":1104},"p":{"d":"986,-278v1,176,-93,278,-267,278r-552,0r0,222r-167,0r0,-778r719,0v171,-2,266,102,267,278xm811,-278v0,-81,-38,-139,-114,-139r-530,0r0,278r530,0v76,0,114,-58,114,-139","w":1141},"q":{"d":"0,-278v-1,-176,93,-278,267,-278r777,2r0,776r-167,0r0,-223r-610,1v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r588,-1r0,-275r-588,-2v-77,0,-114,58,-114,139","w":1211},"r":{"d":"610,-558v134,0,213,83,197,228r-167,0v4,-51,-8,-86,-58,-86r-415,-1r0,417r-167,0r0,-556","w":950},"s":{"d":"913,-170v0,103,-65,170,-175,170r-738,0r0,-131r705,1v37,0,55,-14,55,-43v0,-28,-18,-42,-55,-42r-530,-1v-102,1,-175,-66,-175,-169v0,-101,66,-171,175,-171r708,0r0,131r-675,0v-37,0,-55,14,-55,42v0,28,18,42,55,42r530,1v102,-1,175,67,175,170","w":1039},"t":{"d":"267,-208v1,58,20,77,78,77r425,0r0,131r-504,0v-116,-3,-166,-47,-166,-167r0,-258r-100,0r0,-131r100,0r0,-222r167,0r0,222r503,0r0,131r-503,0r0,217","w":917},"u":{"d":"198,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,358v0,39,19,59,58,59r506,0r0,-417r167,0r0,556r-700,0"},"v":{"d":"167,-139r564,0r0,-417r167,0r0,556r-898,0r0,-556r167,0r0,417"},"w":{"d":"197,0v-115,4,-197,-68,-197,-170r0,-386r167,0r0,358v0,39,19,59,58,59r273,0r0,-417r167,0r0,417r326,0r0,-417r167,0r0,556r-961,0","w":1323},"x":{"d":"132,-208r646,0r0,-131r-646,0r0,131xm1,-138v-2,-70,61,-133,131,-131r0,131r-131,0xm0,-138r132,0r0,138r-132,0r0,-138xm1,-396v-2,71,61,133,131,131r0,-131r-131,0xm0,-396r132,0r0,-158r-132,0r0,158xm909,-138v2,-70,-61,-133,-131,-131r0,131r131,0xm910,-138r-132,0r0,138r132,0r0,-138xm909,-396v2,71,-61,133,-131,131r0,-131r131,0xm910,-396r-132,0r0,-158r132,0r0,158xm133,-454v-2,62,53,117,115,115r-115,0r0,-115xm133,-94v-2,-62,53,-117,115,-115r-115,0r0,115xm777,-454v2,62,-53,117,-115,115r115,0r0,-115xm778,-93v2,-62,-54,-117,-115,-115r115,0r0,115","w":1017},"y":{"d":"754,92v53,-1,68,-31,66,-92r-622,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,336v-1,49,32,82,81,81r572,0r0,-417r167,0r0,576v3,124,-85,207,-204,207r-769,0r0,-135r740,0","w":1169},"z":{"d":"0,-170v0,101,66,170,175,170r738,0r0,-131r-704,1v-37,0,-56,-14,-56,-43v0,-28,19,-42,56,-42r529,-1v102,1,175,-66,175,-169v0,-102,-66,-171,-175,-171r-707,-2r0,131r674,2v37,0,55,14,55,42v0,28,-18,42,-55,42r-530,1v-102,-1,-175,67,-175,170","w":1039},"{":{"d":"0,-466v58,7,98,-17,100,-66v3,-102,-10,-222,10,-308v23,-50,68,-91,143,-91r196,0r0,153r-163,0v-22,0,-33,11,-33,33r0,289v1,35,-29,68,-64,67v36,0,65,30,64,66r0,290v0,22,11,33,33,33r163,0r0,153r-196,0v-87,1,-153,-65,-153,-153r0,-246v-1,-49,-42,-75,-100,-67r0,-153","w":515},"|":{"w":211},"}":{"d":"349,-778v0,-93,-61,-152,-153,-153r-196,0r0,153r163,0v22,0,33,11,33,33r0,289v-1,35,29,68,64,67v-36,0,-65,30,-64,66r0,290v0,22,-11,33,-33,33r-163,0r0,153r196,0v91,0,153,-64,153,-153r0,-246v1,-49,42,-75,100,-67r0,-153v-58,7,-99,-17,-100,-66r0,-246","w":515},"~":{"w":342},"\u0131":{"w":256},"\u00c7":{"w":729},"\u00d6":{"w":1084},"\u00dc":{"w":761},"\u00e7":{"w":578},"\u00f6":{"d":"7,-368v-3,-111,96,-207,207,-207r536,0v112,-3,207,95,207,207r0,162v3,111,-96,207,-207,207r-536,0v-110,3,-207,-97,-207,-207r0,-162xm264,-445v-45,-1,-85,40,-85,85r0,138v-1,45,40,85,85,85r428,0v45,1,85,-40,85,-85r0,-138v1,-45,-40,-85,-85,-85r-428,0xm289,-650r0,-128r379,0r0,128r-379,0","w":1084},"\u00fc":{"d":"198,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,358v0,39,19,59,58,59r506,0r0,-417r167,0r0,556r-700,0xm284,-650r0,-128r379,0r0,128r-379,0","w":1032},"\u00a0":{"w":668}}}); diff --git a/doc/themes/triqs/static/triqs.css b/doc/themes/triqs/static/triqs.css new file mode 100644 index 00000000..e183cb21 --- /dev/null +++ b/doc/themes/triqs/static/triqs.css @@ -0,0 +1,449 @@ +/* + * sphinx13.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- sphinx13 theme. + * + * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; + font-size: 14px; + text-align: center; + background-image: url(bodybg.png); + color: black; + padding: 0; + border-right: 1px solid #0a507a; + border-left: 1px solid #0a507a; + + margin: 0 auto; + min-width: 780px; + max-width: 1080px; +} + + +.red{ + color: red +} +.blue{ + color: blue +} +.green{ + color: green +} + +.param{ + color: blue +} + +a.triqs { + color: #073958; + text-decoration: none; +} + +a.triqs:hover { + color: #0a527f; + text-decoration: none; +} + +.pageheader { + background-color: #dcdcdc; + text-align: left; + padding: 10px 15px; + color: #073958; + border: none; +} + +.pageheader ul { + float: right; + color: #073958; + list-style-type: none; + padding-left: 0; + margin-top: 22px; + margin-right: 10px; +} + +.pageheader li { + float: left; + margin: 0 0 0 10px; +} + +.pageheader li a { + padding: 8px 12px; + color: #073958; + text-shadow: none; +} + +.pageheader li a:hover { + background-color: #f9f9f0; + color: #0a507a; + text-shadow: none; +} + +div.document { + background-color: white; + text-align: left; +} + +div.bodywrapper { + margin: 0 240px 0 0; + border-right: 1px solid #0a507a; +} + +div.body { + margin: 0; + padding: 0.5em 20px 20px 20px; +} + +div.related { + font-size: 1em; + color: white; +} + +div.related ul { + background-image: url(relbg.png); + height: 1.9em; + border-top: 1px solid #002e50; + border-bottom: 1px solid #002e50; +} + +div.related ul li { + margin: 0 5px 0 0; + padding: 0; + float: left; +} + +div.related ul li.right { + float: right; + margin-right: 5px; +} + +div.related ul li a { + margin: 0; + padding: 0 5px 0 5px; + line-height: 1.75em; + color: #f9f9f0; + text-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5); +} + +div.related ul li a:hover { + color: white; + /*text-decoration: underline;*/ + text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.5); +} + +div.sphinxsidebarwrapper { + position: relative; + top: 0px; + padding: 0; +} + +div.sphinxsidebar { + margin: 0; + padding: 0 15px 15px 0; + width: 210px; + float: right; + font-size: 1em; + text-align: left; +} + +div.sphinxsidebar .logo { + font-size: 1.8em; + color: #0A507A; + font-weight: 300; + text-align: center; +} + +div.sphinxsidebar .logo img { + vertical-align: middle; +} + +div.sphinxsidebar input { + border: 1px solid #aaa; + font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; + font-size: 1em; +} + +div.sphinxsidebar h3 { + font-size: 1.5em; + border-top: 1px solid #0a507a; + margin-top: 1em; + margin-bottom: 0.5em; + padding-top: 0.5em; +} + +div.sphinxsidebar h4 { + font-size: 1.2em; + margin-bottom: 0; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4 { + margin-right: -15px; + margin-left: -15px; + padding-right: 14px; + padding-left: 14px; + color: #333; + font-weight: 300; + /*text-shadow: 0px 0px 0.5px rgba(0, 0, 0, 0.4);*/ +} + +div.sphinxsidebarwrapper > h3:first-child { + margin-top: 0.5em; + border: none; +} + +div.sphinxsidebar h3 a { + color: #333; +} + +div.sphinxsidebar ul { + color: #444; + margin-top: 7px; + padding: 0; + line-height: 130%; +} + +div.sphinxsidebar ul ul { + margin-left: 20px; + list-style-image: url(listitem.png); +} + +div.footer { + background-image: url(footerbg.png); + color: #ccc; + text-shadow: 0 0 .2px rgba(255, 255, 255, 0.8); + padding: 3px 8px 3px 0; + clear: both; + font-size: 0.8em; + text-align: right; +} + +/* no need to make a visible link to Sphinx on the Sphinx page */ +div.footer a { + color: #ccc; +} + +/* -- body styles ----------------------------------------------------------- */ + +p { + margin: 0.8em 0 0.5em 0; +} + +a { + color: #A2881D; + text-decoration: none; +} + +a:hover { + color: #E1C13F; +} + +div.body a { + text-decoration: underline; +} + +h1 { + margin: 10px 0 0 0; + font-size: 2.4em; + color: #0A507A; + font-weight: 300; +} + +h2 { + margin: 1.em 0 0.2em 0; + font-size: 1.5em; + font-weight: 300; + padding: 0; + color: #174967; +} + +h3 { + margin: 1em 0 -0.3em 0; + font-size: 1.3em; + font-weight: 300; +} + +div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { + text-decoration: none; +} + +div.body h1 a tt, div.body h2 a tt, div.body h3 a tt, div.body h4 a tt, div.body h5 a tt, div.body h6 a tt { + color: #0A507A !important; + font-size: inherit !important; +} + +a.headerlink { + color: #0A507A !important; + font-size: 12px; + margin-left: 6px; + padding: 0 4px 0 4px; + text-decoration: none !important; + float: right; +} + +a.headerlink:hover { + background-color: #ccc; + color: white!important; +} + +cite, code, tt { + font-family: 'Consolas', 'DejaVu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + font-size: 14px; + letter-spacing: -0.02em; +} + +tt { + background-color: #f2f2f2; + border: 1px solid #ddd; + border-radius: 2px; + color: #333; + padding: 1px; +} + +tt.descname, tt.descclassname, tt.xref { + border: 0; +} + +hr { + border: 1px solid #abc; + margin: 2em; +} + +a tt { + border: 0; + color: #a2881d; +} + +a tt:hover { + color: #e1c13f; +} + +pre { + font-family: 'Consolas', 'DejaVu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + font-size: 13px; + letter-spacing: 0.015em; + line-height: 120%; + padding: 0.5em; + border: 1px solid #ccc; + border-radius: 2px; + background-color: #f8f8f8; +} + +pre a { + color: inherit; + text-decoration: underline; +} + +td.linenos pre { + padding: 0.5em 0; +} + +div.quotebar { + background-color: #f8f8f8; + max-width: 250px; + float: right; + padding: 0px 7px; + border: 1px solid #ccc; + margin-left: 1em; +} + +div.topic { + background-color: #f8f8f8; +} + +table { + border-collapse: collapse; + margin: 0 -0.5em 0 -0.5em; +} + +table td, table th { + padding: 0.2em 0.5em 0.2em 0.5em; +} + +div.admonition, div.warning { + font-size: 0.9em; + margin: 1em 0 1em 0; + border: 1px solid #86989B; + border-radius: 2px; + background-color: #f7f7f7; + padding: 0; +} + +div.admonition p, div.warning p { + margin: 0.5em 1em 0.5em 1em; + padding: 0; +} + +div.admonition pre, div.warning pre { + margin: 0.4em 1em 0.4em 1em; +} + +div.admonition p.admonition-title, +div.warning p.admonition-title { + margin-top: 1em; + padding-top: 0.5em; + font-weight: bold; +} + +div.warning { + border: 1px solid #940000; +/* background-color: #FFCCCF;*/ +} + +div.warning p.admonition-title { +} + +div.admonition ul, div.admonition ol, +div.warning ul, div.warning ol { + margin: 0.1em 0.5em 0.5em 3em; + padding: 0; +} + +div.admonition .highlight, div.warning .highlight { + background-color: #f7f7f7; +} + +.viewcode-back { + font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + + +.my-code-block.std-ref { + color : red; +} + +.cppbrief { + color: #C6792C; + font-style: oblique; +} + +.cppsynopsis { + background-color: #E7EDF9; + /*font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif;*/ + /*font-family: monospace; */ + font-family: Verdana, Arial, Lucida Console; + font-size=80%; + /*font-style: oblique;*/ + /* white-space: pre;*/ +} + + + diff --git a/doc/themes/triqs/theme.conf b/doc/themes/triqs/theme.conf new file mode 100644 index 00000000..96ca439a --- /dev/null +++ b/doc/themes/triqs/theme.conf @@ -0,0 +1,4 @@ +[theme] +inherit = basic +stylesheet = triqs.css +pygments_style = sphinx diff --git a/share/cmake/Modules/FindSphinx.cmake b/share/cmake/Modules/FindSphinx.cmake new file mode 100644 index 00000000..b8cc28a8 --- /dev/null +++ b/share/cmake/Modules/FindSphinx.cmake @@ -0,0 +1,37 @@ +# Copyright Olivier Parcollet 2017. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# This module looks for sphinx documentation tool +# and define a function that prepares the Makefile for sphinx-build + +find_program(SPHINXBUILD_EXECUTABLE + NAMES sphinx-build + PATHS /usr/bin /opt/local/bin /usr/local/bin #opt/sphinx-doc/bin + PATH_SUFFIXES bin + ) + +if (NOT SPHINXBUILD_EXECUTABLE) + message(FATAL_ERROR "I cannot find sphinx to build the triqs documentation") +endif() + +execute_process( + COMMAND "${SPHINXBUILD_EXECUTABLE}" --version + OUTPUT_VARIABLE SPHINXBUILD_VERSION + ERROR_VARIABLE SPHINXBUILD_VERSION + ) +if (SPHINXBUILD_VERSION MATCHES "[Ss]phinx.* ([0-9]+\\.[0-9]+(\\.|b)[0-9]+)") + set (SPHINXBUILD_VERSION "${CMAKE_MATCH_1}") +endif() + +if (SPHINXBUILD_VERSION VERSION_EQUAL 1.6.3) + message(FATAL_ERROR "sphinx-build found at ${SPHINXBUILD_EXECUTABLE} but version 1.6.3 has a bug. Upgrade sphinx.") +else() + message(STATUS "sphinx-build program found at ${SPHINXBUILD_EXECUTABLE} with version ${SPHINXBUILD_VERSION}") +endif () + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SPHINX DEFAULT_MSG SPHINXBUILD_EXECUTABLE) + +mark_as_advanced( SPHINXBUILD_EXECUTABLE )