|
From: <fer...@us...> - 2009-03-18 07:39:53
|
Revision: 6987
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6987&view=rev
Author: fer_perez
Date: 2009-03-18 07:39:43 +0000 (Wed, 18 Mar 2009)
Log Message:
-----------
Update to current versions of tools, add API auto generation.
Modified Paths:
--------------
trunk/py4science/examples/sphinx_template2/Makefile
trunk/py4science/examples/sphinx_template2/conf.py
trunk/py4science/examples/sphinx_template2/index.rst
trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst
trunk/py4science/examples/sphinx_template2/simulations/finale.rst
trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst
trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py
Added Paths:
-----------
trunk/py4science/examples/sphinx_template2/_static/
trunk/py4science/examples/sphinx_template2/_templates/
trunk/py4science/examples/sphinx_template2/api/
trunk/py4science/examples/sphinx_template2/api/generated/
trunk/py4science/examples/sphinx_template2/api/index.rst
trunk/py4science/examples/sphinx_template2/autogen_api.py
trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py
trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py
trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py
trunk/py4science/examples/sphinx_template2/tools/sphinxext/numpydoc.py
Removed Paths:
-------------
trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py
trunk/py4science/examples/sphinx_template2/tools/sphinxext/only_directives.py
trunk/py4science/examples/sphinx_template2/tools/sphinxext/plot_directive.py
trunk/py4science/examples/sphinx_template2/tools/static/
trunk/py4science/examples/sphinx_template2/tools/templates/
Modified: trunk/py4science/examples/sphinx_template2/Makefile
===================================================================
--- trunk/py4science/examples/sphinx_template2/Makefile 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/Makefile 2009-03-18 07:39:43 UTC (rev 6987)
@@ -14,7 +14,8 @@
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR)
-.PHONY: help clean html web pickle htmlhelp latex changes linkcheck pdf all dist
+.PHONY: help clean html web pickle htmlhelp latex changes linkcheck pdf all \
+ dist api
help:
@echo "Please use \`make <target>' where <target> is one of"
@@ -31,7 +32,7 @@
@echo " dist all, and then puts the results in dist/"
clean:
- -rm -rf build/ dist/ _static/ pyplots/*png pyplots/*pdf
+ -rm -rf build/ dist/ _static/* api/generated/*rst pyplots/*png pyplots/*pdf
pdf: latex
cd build/latex && make all-pdf
@@ -44,12 +45,16 @@
cp -al build/html dist/
@echo "Build finished. Final docs are in dist/"
-html:
+html: api
mkdir -p build/html build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
@echo
@echo "Build finished. The HTML pages are in build/html."
+api:
+ python autogen_api.py
+ @echo "Build API docs finished."
+
pickle:
mkdir -p build/pickle build/doctrees
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
@@ -60,14 +65,14 @@
web: pickle
-htmlhelp:
+htmlhelp: api
mkdir -p build/htmlhelp build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in build/htmlhelp."
-latex:
+latex: api
mkdir -p build/latex build/doctrees
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
@echo
Property changes on: trunk/py4science/examples/sphinx_template2/_static
___________________________________________________________________
Added: svn:mergeinfo
+
Property changes on: trunk/py4science/examples/sphinx_template2/_templates
___________________________________________________________________
Added: svn:mergeinfo
+
Added: trunk/py4science/examples/sphinx_template2/api/index.rst
===================================================================
--- trunk/py4science/examples/sphinx_template2/api/index.rst (rev 0)
+++ trunk/py4science/examples/sphinx_template2/api/index.rst 2009-03-18 07:39:43 UTC (rev 6987)
@@ -0,0 +1,12 @@
+.. _api-index:
+
+########################
+ The Python email API
+########################
+
+.. htmlonly::
+
+ :Release: |version|
+ :Date: |today|
+
+.. include:: generated/gen.rst
Added: trunk/py4science/examples/sphinx_template2/autogen_api.py
===================================================================
--- trunk/py4science/examples/sphinx_template2/autogen_api.py (rev 0)
+++ trunk/py4science/examples/sphinx_template2/autogen_api.py 2009-03-18 07:39:43 UTC (rev 6987)
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+"""Script to auto-generate our API docs.
+"""
+# stdlib imports
+import os
+import sys
+
+# local imports
+sys.path.append(os.path.abspath('tools/sphinxext'))
+from apigen import ApiDocWriter
+
+#*****************************************************************************
+if __name__ == '__main__':
+ pjoin = os.path.join
+ package = 'email'
+ outdir = pjoin('api','generated')
+ docwriter = ApiDocWriter(package,rst_extension='.rst')
+ # Skip packages you don't want to document
+ docwriter.package_skip_patterns += [r'\.mime',
+ ]
+ # For modules, there are also skip patterns
+ docwriter.module_skip_patterns += [ r'\.mime',
+ ]
+ docwriter.write_api_docs(outdir)
+ docwriter.write_index(outdir, 'gen',
+ relative_to = 'api'
+ )
+ print '%d files written' % len(docwriter.written_modules)
Property changes on: trunk/py4science/examples/sphinx_template2/autogen_api.py
___________________________________________________________________
Added: svn:executable
+ *
Modified: trunk/py4science/examples/sphinx_template2/conf.py
===================================================================
--- trunk/py4science/examples/sphinx_template2/conf.py 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/conf.py 2009-03-18 07:39:43 UTC (rev 6987)
@@ -28,14 +28,17 @@
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = [#'mathmpl',
- 'ipython_console_highlighting', 'sphinx.ext.autodoc',
- 'inheritance_diagram', 'only_directives', 'plot_directive',
- 'sphinx.ext.pngmath',
- ]
+extensions = ['matplotlib.sphinxext.mathmpl',
+ 'matplotlib.sphinxext.only_directives',
+ 'matplotlib.sphinxext.plot_directive',
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.doctest',
+ 'ipython_console_highlighting',
+ 'inheritance_diagram',
+ 'numpydoc']
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['tools/templates']
+templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
@@ -102,7 +105,7 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['tools/static','_static']
+html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
Modified: trunk/py4science/examples/sphinx_template2/index.rst
===================================================================
--- trunk/py4science/examples/sphinx_template2/index.rst 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/index.rst 2009-03-18 07:39:43 UTC (rev 6987)
@@ -13,8 +13,9 @@
.. toctree::
:maxdepth: 2
- model/index.rst
- simulations/index.rst
+ model/index
+ simulations/index
+ api/index
.. htmlonly::
Modified: trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst
===================================================================
--- trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/model/sphinx_helpers.rst 2009-03-18 07:39:43 UTC (rev 6987)
@@ -157,7 +157,7 @@
original source code, a high-resolution PNG and a PDF. In the PDF
version of the document, the plot is included as a scalable PDF.
-.. plot:: ../pyplots/elegant.py
+.. plot:: pyplots/elegant.py
:include-source:
Inheritance diagrams
Modified: trunk/py4science/examples/sphinx_template2/simulations/finale.rst
===================================================================
--- trunk/py4science/examples/sphinx_template2/simulations/finale.rst 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/simulations/finale.rst 2009-03-18 07:39:43 UTC (rev 6987)
@@ -8,5 +8,6 @@
After much head scratching, I wrote this big elegant piece of code, to
produce this much more elegant figure:
-.. plot:: ../pyplots/elegant.py
+.. plot:: pyplots/fancy.py
:include-source:
+
Modified: trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst
===================================================================
--- trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/simulations/preliminary.rst 2009-03-18 07:39:43 UTC (rev 6987)
@@ -6,6 +6,6 @@
I wrote this big hairy piece of code to make the following plot:
-.. plot:: ../pyplots/hairy.py
+.. plot:: pyplots/hairy.py
:include-source:
Added: trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py
===================================================================
--- trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py (rev 0)
+++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/apigen.py 2009-03-18 07:39:43 UTC (rev 6987)
@@ -0,0 +1,426 @@
+"""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(object):
+ ''' 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(object): ")
+ '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' \
+ '\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()
Added: trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py
===================================================================
--- trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py (rev 0)
+++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape.py 2009-03-18 07:39:43 UTC (rev 6987)
@@ -0,0 +1,497 @@
+"""Extract reference documentation from the NumPy source tree.
+
+"""
+
+import inspect
+import textwrap
+import re
+import pydoc
+from StringIO import StringIO
+from warnings import warn
+4
+class Reader(object):
+ """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(object):
+ 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 not self._parsed_data.has_key(key):
+ 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<role>\w+):`(?P<name>[a-zA-Z0-9_.-]+)`|"
+ r" (?P<name2>[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.iteritems():
+ 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, 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, 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 not roles.has_key(self._role):
+ 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
+
+
Added: trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py
===================================================================
--- trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py (rev 0)
+++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/docscrape_sphinx.py 2009-03-18 07:39:43 UTC (rev 6987)
@@ -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.iteritems():
+ 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)
+
Modified: trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py
===================================================================
--- trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/inheritance_diagram.py 2009-03-18 07:39:43 UTC (rev 6987)
@@ -29,42 +29,30 @@
LaTeX.
"""
-#-----------------------------------------------------------------------------
-# Module and package imports
-
-# From the standard library
-
import inspect
import os
import re
import subprocess
-
try:
from hashlib import md5
except ImportError:
from md5 import md5
-# Third party
from docutils.nodes import Body, Element
-from docutils.writers.html4css1 import HTMLTranslator
from docutils.parsers.rst import directives
-
-from sphinx.latexwriter import LaTeXTranslator
from sphinx.roles import xfileref_role
-#-----------------------------------------------------------------------------
-# Global Constants
-# Sphinx automatically copies out the contents of this directory to the html
-# output, so by putting things in here they get correctly picked up in the end
-STATIC_DIR='_static'
+def my_import(name):
+ """Module importer - taken from the python documentation.
-options_spec = {
- 'parts': directives.nonnegative_int
- }
+ 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
-#-----------------------------------------------------------------------------
-# Main code begins, classes and functions
-
class DotException(Exception):
pass
@@ -105,11 +93,15 @@
path = (path and path.rstrip('.'))
if not path:
path = base
- if not path:
- raise ValueError(
- "Invalid class or module '%s' specified for inheritance diagram" % name)
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)
@@ -201,7 +193,6 @@
def _format_node_options(self, options):
return ','.join(["%s=%s" % x for x in options.items()])
-
def _format_graph_options(self, options):
return ''.join(["%s=%s;\n" % x for x in options.items()])
@@ -292,7 +283,6 @@
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
@@ -300,13 +290,16 @@
"""
pass
-
-def inheritance_diagram_directive_run(class_names, options, state):
+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)
@@ -326,11 +319,9 @@
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
@@ -341,16 +332,13 @@
graph_hash = get_graph_hash(node)
name = "inheritance%s" % graph_hash
- png_path = os.path.join(STATIC_DIR, name + ".png")
+ 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
- path = STATIC_DIR
- source = self.document.attributes['source']
- count = source.split('/doc/')[-1].count('/')
- for i in range(count):
- if os.path.exists(path): break
- path = '../'+path
- path = '../'+path #specifically added for matplotlib
-
# Create a mapping from fully-qualified class names to URLs.
urls = {}
for child in node:
@@ -366,7 +354,6 @@
return ('<img src="%s/%s.png" usemap="#%s" class="inheritance"/>%s' %
(path, name, name, image_map))
-
def latex_output_graph(self, node):
"""
Output the graph for LaTeX. This will insert a PDF.
@@ -376,13 +363,15 @@
graph_hash = get_graph_hash(node)
name = "inheritance%s" % graph_hash
- pdf_path = os.path.join(STATIC_DIR, name + ".pdf")
+ 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 '\\includegraphics{../../%s}' % pdf_path
+ 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
@@ -402,57 +391,17 @@
node.children = []
return visitor
-
def do_nothing(self, node):
pass
-
def setup(app):
- app.add_node(inheritance_diagram)
+ setup.app = app
+ setup.confdir = app.confdir
- HTMLTranslator.visit_inheritance_diagram = \
- visit_inheritance_diagram(html_output_graph)
- HTMLTranslator.depart_inheritance_diagram = do_nothing
-
- LaTeXTranslator.visit_inheritance_diagram = \
- visit_inheritance_diagram(latex_output_graph)
- LaTeXTranslator.depart_inheritance_diagram = do_nothing
-
-#-----------------------------------------------------------------------------
-# Main code - register the directives. Do it in a way that's compatible with
-# the old and current docutils APIs.
-
-try:
- from docutils.parsers.rst import Directive
-except ImportError:
- # Legacy API
- from docutils.parsers.rst.directives import _directives
-
- def inheritance_diagram_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state,
- state_machine):
- return inheritance_diagram_directive_run(arguments, options, state)
-
- inheritance_diagram_directive.__doc__ = __doc__
- inheritance_diagram_directive.arguments = (1, 100, 0)
- inheritance_diagram_directive.options = options_spec
- inheritance_diagram_directive.content = 0
- _directives['inheritance-diagram'] = inheritance_diagram_directive
-
-else:
- # New API
- class inheritance_diagram_directive(Directive):
- has_content = False
- required_arguments = 1
- optional_arguments = 100
- final_argument_whitespace = False
- option_spec = options_spec
-
- def run(self):
- return inheritance_diagram_directive_run(
- self.arguments, self.options, self.state)
-
- inheritance_diagram_directive.__doc__ = __doc__
-
- directives.register_directive('inheritance-diagram',
- inheritance_diagram_directive)
+ 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)
Deleted: trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py
===================================================================
--- trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py 2009-03-17 19:45:05 UTC (rev 6986)
+++ trunk/py4science/examples/sphinx_template2/tools/sphinxext/mathmpl.py 2009-03-18 07:39:43 UTC (rev 6987)
@@ -1,166 +0,0 @@
-"""matplotlib-based directive for math rendering in reST using sphinx.
-
-To use this extension, add ``mathmpl`` to the list of extensions in
-:file:`conf.py`.
-
-*Warning*: this code is currently untested. ***MAY NOT WORK***
-
-Note:
-
-Current SVN versions of Sphinx now include built-in support for math.
-There are two flavors:
-
- - pngmath: uses dvipng to render the equation
-
- - jsmath: renders the math in the browser using Javascript
-
-To use these extensions instead of the code in this module, add
-``sphinx.ext.pngmath`` or ``sphinx.ext.jsmath`` to the list of extensions in
-:file:`conf.py`.
-
-All three of these options for math are designed to behave in the same
-way.
-"""
-
-import os
-try:
- from hashlib import md5
-except ImportError:
- from md5 import md5
-
-from docutils import nodes
-from docutils.parsers.rst import directives
-from docutils.writers.html4css1 import HTMLTranslator
-from sphinx.latexwriter import LaTeXTranslator
-import warnings
-
-# Constants
-STATIC_DIR='_static'
-
-# Define LaTeX math node:
-class latex_math(nodes.General, nodes.Element):
- pass
-
-def fontset_choice(arg):
- return directives.choice(arg, ['cm', 'stix', 'stixsans'])
-
-options_spec = {'fontset': fontset_choice}
-
-def math_role(role, rawtext, text, lineno, inliner,
- options={}, content=[]):
- i = rawtext.find('`')
- latex = rawtext[i+1:-1]
- node = latex_math(rawtext)
- node['latex'] = latex
- node['fontset'] = options.get('fontset', 'cm')
- return [node], []
-math_role.options = options_spec
-
-def math_directive_run(content, block_text, options):
- latex = ''.join(content)
- node = latex_math(block_text)
- node['latex'] = latex
- node['fontset'] = options.get('fontset', 'cm')
- return [node]
-
-try:
- from docutils.parsers.rst import Directive
-except ImportError:
- # Register directive the old way:
- from docutils.parsers.rst.directives import _directives
- def math_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- return math_directive_run(content, block_text, options)
- math_directive.arguments = None
- math_directive.options = options_spec
- math_directive.content = 1
- _directives['math'] = math_directive
-else:
- class math_directive(Directive):
- has_content = True
- option_spec = options_spec
-
- def run(self):
- return math_directive_run(self.content, self.block_text,
- self.options)
- from docutils.parsers.rst import directives
- directives.register_directive('math', math_directive)
-
-def setup(app):
- app.add_node(latex_math)
- app.add_role('math', math_role)
-
- # Add visit/depart methods to HTML-Translator:
- def visit_latex_math_html(self, node):
- source = self.document.attributes['source']
- self.body.append(latex2html(node, source))
- def depart_latex_math_html(self, node):
- pass
- HTMLTranslator.visit_latex_math = visit_latex_math_html
- HTMLTranslator.depart_latex_math = depart_latex_math_html
-
- # Add visit/depart methods to LaTeX-Translator:
- def visit_latex_math_latex(self, node):
- inline = isinstance(node.parent, nodes.TextElement)
- if inline:
- self.body.append('$%s$' % node['latex'])
- else:
- self.body.extend(['\\begin{equation}',
- node['latex'],
- '\\end{equation}'])
- def depart_latex_math_latex(self, node):
- pass
- LaTeXTranslator.visit_latex_math = visit_latex_math_latex
- LaTeXTranslator.depart_latex_math = depart_latex_math_latex
-
-from matplotlib import rcParams
-from matplotlib.mathtext import MathTextParser
-rcParams['mathtext.fontset'] = 'cm'
-mathtext_parser = MathTextParser("Bitmap")
-
-
-# This uses mathtext to render the expression
-def latex2png(latex, filename, fontset='cm'):
- latex = "$%s$" % latex
- orig_fontset = rcParams['mathtext.fontset']
- rcParams['mathtext.fontset'] = fontset
- if os.path.exists(filename):
- depth = mathtext_parser.get_depth(latex, dpi=100)
- else:
- print latex.encode("ascii", "backslashreplace")
- try:
- depth = mathtext_parser.to_png(filename, latex, dpi=100)
- except:
- warnings.warn("Could not render math expression %s" % latex,
- Warning)
- depth = 0
- rcParams['mathtext.fontset'] = orig_fontset
- return depth
-
-# LaTeX to HTML translation stuff:
-def latex2html(node, source):
- inline = isinstance(node.parent, nodes.TextElement)
- latex = node['latex']
- name = 'math-%s' % md5(latex).hexdigest()[-10:]
- dest = os.path.join(STATIC_DIR, name + ".png")
-
- depth = latex2png(latex, dest, node.get('fontset',
- rcParams['mathtext.fontset']))
-
- path = STATIC_DIR
- count = source.split('/doc/')[-1].count('/')
- for i in range(count):
- if os.path.exists(path): break
- path = '../'+path
- path = '../'+path #s...
[truncated message content] |