summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2011-07-07 19:50:11 +0200
committerGeorg Brandl <georg@python.org>2011-07-07 19:50:11 +0200
commit50bbb1a5e764ad72879f1ce5a6ddbdcfba5cfe08 (patch)
tree6251a2c44945150541824f691d524d5dd7c8bef0
parentec2ac36d5fdec3d52009bcc24b7d3336ee3a9bef (diff)
parent09e2e6e04d81d325b9b985fdb2a4965ffde7a24c (diff)
downloadsphinx-50bbb1a5e764ad72879f1ce5a6ddbdcfba5cfe08.tar.gz
Merged in jonwaltman/sphinx-info (pull request #5)
-rw-r--r--CHANGES3
-rw-r--r--LICENSE27
-rw-r--r--doc/ext/autosummary.rst14
-rw-r--r--doc/markup/para.rst2
-rw-r--r--doc/rest.rst4
-rw-r--r--sphinx/builders/gettext.py43
-rw-r--r--sphinx/ext/autosummary/__init__.py91
-rw-r--r--sphinx/ext/autosummary/generate.py6
-rw-r--r--sphinx/ext/mathbase.py5
-rw-r--r--sphinx/themes/basic/static/underscore.js7
-rw-r--r--sphinx/util/nodes.py13
-rw-r--r--tests/root/autosummary.txt24
-rw-r--r--tests/test_autosummary.py8
13 files changed, 199 insertions, 48 deletions
diff --git a/CHANGES b/CHANGES
index 501c5912..47ac85a6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -91,6 +91,9 @@ Features added
- #367: Added automatic exclusion of hidden members in inheritance
diagrams, and an option to selectively enable it.
- Added :confval:`pngmath_add_tooltips`.
+ - The math extension displaymath directives now support ``name`` in
+ addition to ``label`` for giving the equation label, for compatibility
+ with Docutils.
* New locales:
diff --git a/LICENSE b/LICENSE
index fa1ef995..260c20fb 100644
--- a/LICENSE
+++ b/LICENSE
@@ -217,3 +217,30 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------
+
+The included Underscore JavaScript library is available under the MIT
+license:
+
+----------------------------------------------------------------------
+Copyright (c) 2009 Jeremy Ashkenas, DocumentCloud
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/doc/ext/autosummary.rst b/doc/ext/autosummary.rst
index 9f66e510..878a3c2c 100644
--- a/doc/ext/autosummary.rst
+++ b/doc/ext/autosummary.rst
@@ -19,19 +19,21 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts:
contain links to the documented items, and short summary blurbs extracted
from their docstrings.
-2. The convenience script :program:`sphinx-autogen` or the new
+2. Optionally, the convenience script :program:`sphinx-autogen` or the new
:confval:`autosummary_generate` config value can be used to generate short
"stub" files for the entries listed in the :rst:dir:`autosummary` directives.
- These by default contain only the corresponding :mod:`sphinx.ext.autodoc`
- directive.
+ These files by default contain only the corresponding :mod:`sphinx.ext.autodoc`
+ directive, but can be customized with templates.
.. rst:directive:: autosummary
Insert a table that contains links to documented items, and a short summary
- blurb (the first sentence of the docstring) for each of them. The
- :rst:dir:`autosummary` directive can also optionally serve as a :rst:dir:`toctree`
- entry for the included items.
+ blurb (the first sentence of the docstring) for each of them.
+
+ The :rst:dir:`autosummary` directive can also optionally serve as a
+ :rst:dir:`toctree` entry for the included items. Optionally, stub
+ ``.rst`` files for these items can also be automatically generated.
For example, ::
diff --git a/doc/markup/para.rst b/doc/markup/para.rst
index ced18d81..b532bc63 100644
--- a/doc/markup/para.rst
+++ b/doc/markup/para.rst
@@ -145,7 +145,7 @@ The :rst:dir:`toctree` directive, which generates tables of contents of
subdocuments, is described in :ref:`toctree-directive`.
For local tables of contents, use the standard reST :dudir:`contents directive
-<contents>`.
+<table-of-contents>`.
Glossary
diff --git a/doc/rest.rst b/doc/rest.rst
index 69307572..db832ed8 100644
--- a/doc/rest.rst
+++ b/doc/rest.rst
@@ -275,8 +275,8 @@ Docutils supports the following directives:
* Additional body elements:
- - :dudir:`contents` (a local, i.e. for the current file only, table of
- contents)
+ - :dudir:`contents <table-of-contents>` (a local, i.e. for the current file
+ only, table of contents)
- :dudir:`container` (a container with a custom class, useful to generate an
outer ``<div>`` in HTML)
- :dudir:`rubric` (a heading without relation to the document sectioning)
diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py
index f030750e..fbe8afbb 100644
--- a/sphinx/builders/gettext.py
+++ b/sphinx/builders/gettext.py
@@ -43,6 +43,20 @@ msgstr ""
"""[1:]
+class Catalog(object):
+ """Catalog of translatable messages."""
+
+ def __init__(self):
+ self.messages = [] # retain insertion order, a la OrderedDict
+ self.metadata = {} # msgid -> file, line, uid
+
+ def add(self, msg, origin):
+ if msg not in self.metadata: # faster lookup in hash
+ self.messages.append(msg)
+ self.metadata[msg] = []
+ self.metadata[msg].append((origin.source, origin.line, origin.uid))
+
+
class I18nBuilder(Builder):
"""
General i18n builder.
@@ -52,7 +66,7 @@ class I18nBuilder(Builder):
def init(self):
Builder.init(self)
- self.catalogs = defaultdict(dict)
+ self.catalogs = defaultdict(Catalog)
def get_target_uri(self, docname, typ=None):
return ''
@@ -67,12 +81,7 @@ class I18nBuilder(Builder):
catalog = self.catalogs[docname.split(SEP, 1)[0]]
for node, msg in extract_messages(doctree):
- if not msg in catalog:
- catalog[msg] = []
- if node.source and node.line:
- position = {"source": node.source,
- "line": node.line}
- catalog[msg].append(position)
+ catalog.add(msg, node)
class MessageCatalogBuilder(I18nBuilder):
@@ -90,7 +99,7 @@ class MessageCatalogBuilder(I18nBuilder):
# XXX should supply tz
ctime = datetime.now().strftime('%Y-%m-%d %H:%M%z'),
)
- for section, messages in self.status_iterator(
+ for section, catalog in self.status_iterator(
self.catalogs.iteritems(), "writing message catalogs... ",
lambda (section, _):darkgreen(section), len(self.catalogs)):
@@ -98,14 +107,22 @@ class MessageCatalogBuilder(I18nBuilder):
pofile = open(pofn, 'w', encoding='utf-8')
try:
pofile.write(POHEADER % data)
- for message, positions in messages.iteritems():
+
+ for message in catalog.messages:
+ positions = catalog.metadata[message]
+
+ # generate "#: file1:line1 file2:line2 ..."
+ pofile.write(u"#: %s\n" % ", ".join("%s:%s" %
+ (path.relpath(source, self.srcdir), line)
+ for source, line, _ in positions))
+ # generate "# uuid1\n# uuid2\n ..."
+ pofile.write(u"# %s\n" % "\n# ".join(uid for _, _, uid
+ in positions))
+
# message contains *one* line of text ready for translation
message = message.replace(u'\\', ur'\\'). \
replace(u'"', ur'\"')
- for position in positions:
- source = path.relpath(position["source"], self.outdir)
- line = position["line"]
- pofile.write(u'#: %s:%d\n' % (source, line))
pofile.write(u'msgid "%s"\nmsgstr ""\n\n' % message)
+
finally:
pofile.close()
diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py
index aad8b9f6..32dcc3e4 100644
--- a/sphinx/ext/autosummary/__init__.py
+++ b/sphinx/ext/autosummary/__init__.py
@@ -125,22 +125,39 @@ def autosummary_table_visit_html(self, node):
# -- autodoc integration -------------------------------------------------------
-try:
- ismemberdescriptor = inspect.ismemberdescriptor
- isgetsetdescriptor = inspect.isgetsetdescriptor
-except AttributeError:
- def ismemberdescriptor(obj):
- return False
- isgetsetdescriptor = ismemberdescriptor
+class FakeDirective:
+ env = {}
+ genopt = {}
def get_documenter(obj, parent):
"""Get an autodoc.Documenter class suitable for documenting the given
object.
+
+ *obj* is the Python object to be documented, and *parent* is an
+ another Python object (e.g. a module or a class) to which *obj*
+ belongs to.
"""
- from sphinx.ext.autodoc import AutoDirective, DataDocumenter
+ from sphinx.ext.autodoc import AutoDirective, DataDocumenter, \
+ ModuleDocumenter
+
+ if inspect.ismodule(obj):
+ # ModuleDocumenter.can_document_member always returns False
+ return ModuleDocumenter
+ # Construct a fake documenter for *parent*
+ if parent is not None:
+ parent_doc_cls = get_documenter(parent, None)
+ else:
+ parent_doc_cls = ModuleDocumenter
+
+ if hasattr(parent, '__name__'):
+ parent_doc = parent_doc_cls(FakeDirective(), parent.__name__)
+ else:
+ parent_doc = parent_doc_cls(FakeDirective(), "")
+
+ # Get the corrent documenter class for *obj*
classes = [cls for cls in AutoDirective._registry.values()
- if cls.can_document_member(obj, '', False, parent)]
+ if cls.can_document_member(obj, '', False, parent_doc)]
if classes:
classes.sort(key=lambda cls: cls.priority)
return classes[-1]
@@ -154,7 +171,7 @@ class Autosummary(Directive):
"""
Pretty table containing short signatures and summaries of functions etc.
- autosummary also generates a (hidden) toctree:: node.
+ autosummary can also optionally generate a hidden toctree:: node.
"""
required_arguments = 0
@@ -214,10 +231,7 @@ class Autosummary(Directive):
"""
env = self.state.document.settings.env
- prefixes = ['']
- currmodule = env.temp_data.get('py:module')
- if currmodule:
- prefixes.insert(0, currmodule)
+ prefixes = get_import_prefixes_from_env(env)
items = []
@@ -322,13 +336,29 @@ class Autosummary(Directive):
def mangle_signature(sig, max_chars=30):
"""Reformat a function signature to a more compact form."""
- sig = re.sub(r"^\((.*)\)$", r"\1", sig) + ", "
- r = re.compile(r"(?P<name>[a-zA-Z0-9_*]+)(?P<default>=.*?)?, ")
- items = r.findall(sig)
+ s = re.sub(r"^\((.*)\)$", r"\1", sig).strip()
+
+ # Strip strings (which can contain things that confuse the code below)
+ s = re.sub(r"\\\\", "", s)
+ s = re.sub(r"\\'", "", s)
+ s = re.sub(r"'[^']*'", "", s)
+
+ # Parse the signature to arguments + options
+ args = []
+ opts = []
+
+ opt_re = re.compile(r"^(.*, |)([a-zA-Z0-9_*]+)=")
+ while s:
+ m = opt_re.search(s)
+ if not m:
+ # The rest are arguments
+ args = s.split(', ')
+ break
- args = [name for name, default in items if not default]
- opts = [name for name, default in items if default]
+ opts.insert(0, m.group(2))
+ s = m.group(1)[:-2]
+ # Produce a more compact signature
sig = limited_join(", ", args, max_chars=max_chars-2)
if opts:
if not sig:
@@ -364,6 +394,26 @@ def limited_join(sep, items, max_chars=30, overflow_marker="..."):
# -- Importing items -----------------------------------------------------------
+def get_import_prefixes_from_env(env):
+ """
+ Obtain current Python import prefixes (for `import_by_name`)
+ from ``document.env``
+ """
+ prefixes = [None]
+
+ currmodule = env.temp_data.get('py:module')
+ if currmodule:
+ prefixes.insert(0, currmodule)
+
+ currclass = env.temp_data.get('py:class')
+ if currclass:
+ if currmodule:
+ prefixes.insert(0, currmodule + "." + currclass)
+ else:
+ prefixes.insert(0, currclass)
+
+ return prefixes
+
def import_by_name(name, prefixes=[None]):
"""Import a Python object that has the given *name*, under one of the
*prefixes*. The first name that succeeds is used.
@@ -436,8 +486,7 @@ def autolink_role(typ, rawtext, etext, lineno, inliner,
'obj', rawtext, etext, lineno, inliner, options, content)
pnode = r[0][0]
- prefixes = [None]
- #prefixes.insert(0, inliner.document.settings.env.currmodule)
+ prefixes = get_import_prefixes_from_env(env)
try:
name, obj, parent = import_by_name(pnode['reftarget'], prefixes)
except ImportError:
diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py
index fecb5689..089d181f 100644
--- a/sphinx/ext/autosummary/generate.py
+++ b/sphinx/ext/autosummary/generate.py
@@ -232,7 +232,7 @@ def find_autosummary_in_lines(lines, module=None, filename=None):
*template* ``None`` if the directive does not have the
corresponding options set.
"""
- autosummary_re = re.compile(r'^\s*\.\.\s+autosummary::\s*')
+ autosummary_re = re.compile(r'^(\s*)\.\.\s+autosummary::\s*')
automodule_re = re.compile(
r'^\s*\.\.\s+automodule::\s*([A-Za-z0-9_.]+)\s*$')
module_re = re.compile(
@@ -247,6 +247,7 @@ def find_autosummary_in_lines(lines, module=None, filename=None):
template = None
current_module = module
in_autosummary = False
+ base_indent = ""
for line in lines:
if in_autosummary:
@@ -277,7 +278,7 @@ def find_autosummary_in_lines(lines, module=None, filename=None):
documented.append((name, toctree, template))
continue
- if not line.strip():
+ if not line.strip() or line.startswith(base_indent + " "):
continue
in_autosummary = False
@@ -285,6 +286,7 @@ def find_autosummary_in_lines(lines, module=None, filename=None):
m = autosummary_re.match(line)
if m:
in_autosummary = True
+ base_indent = m.group(1)
toctree = None
template = None
continue
diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py
index b5473449..1a2ca6af 100644
--- a/sphinx/ext/mathbase.py
+++ b/sphinx/ext/mathbase.py
@@ -56,6 +56,7 @@ class MathDirective(Directive):
final_argument_whitespace = True
option_spec = {
'label': directives.unchanged,
+ 'name': directives.unchanged,
'nowrap': directives.flag,
}
@@ -65,7 +66,9 @@ class MathDirective(Directive):
latex = self.arguments[0] + '\n\n' + latex
node = displaymath()
node['latex'] = latex
- node['label'] = self.options.get('label', None)
+ node['label'] = self.options.get('name', None)
+ if node['label'] is None:
+ node['label'] = self.options.get('label', None)
node['nowrap'] = 'nowrap' in self.options
node['docname'] = self.state.document.settings.env.docname
ret = [node]
diff --git a/sphinx/themes/basic/static/underscore.js b/sphinx/themes/basic/static/underscore.js
index 9146e086..5d899143 100644
--- a/sphinx/themes/basic/static/underscore.js
+++ b/sphinx/themes/basic/static/underscore.js
@@ -1,3 +1,10 @@
+// Underscore.js 0.5.5
+// (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the terms of the MIT license.
+// Portions of Underscore are inspired by or borrowed from Prototype.js,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore/
(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index a241f574..682ea77b 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -22,16 +22,25 @@ from sphinx.util.pycompat import class_types
explicit_title_re = re.compile(r'^(.+?)\s*(?<!\x00)<(.*?)>$', re.DOTALL)
caption_ref_re = explicit_title_re # b/w compat alias
-
+IGNORED_NODES = (
+ nodes.Invisible,
+ nodes.Inline,
+ nodes.literal_block,
+ nodes.doctest_block,
+ #XXX there are probably more
+)
def extract_messages(doctree):
"""Extract translatable messages from a document tree."""
for node in doctree.traverse(nodes.TextElement):
- if isinstance(node, (nodes.Invisible, nodes.Inline)):
+ if not node.source:
+ continue # built-in message
+ if isinstance(node, IGNORED_NODES):
continue
# <field_name>orphan</field_name>
# XXX ignore all metadata (== docinfo)
if isinstance(node, nodes.field_name) and node.children[0] == 'orphan':
continue
+
msg = node.rawsource.replace('\n', ' ').strip()
# XXX nodes rendering empty are likely a bug in sphinx.addnodes
if msg:
diff --git a/tests/root/autosummary.txt b/tests/root/autosummary.txt
index edf75e32..82cec7fd 100644
--- a/tests/root/autosummary.txt
+++ b/tests/root/autosummary.txt
@@ -5,3 +5,27 @@ Autosummary test
:toctree: generated
sphinx.application.TemplateBridge
+
+.. currentmodule:: sphinx.application
+
+.. autoclass:: TemplateBridge
+
+ Basic test
+
+ .. autosummary::
+
+ render -- some ignored stuff goes here
+ render_string More ignored stuff
+
+ Test with tildes
+
+ .. autosummary::
+
+ ~TemplateBridge.render
+ ~TemplateBridge.render_string
+
+ Methods:
+
+ .. automethod:: render
+
+ .. automethod:: render_string
diff --git a/tests/test_autosummary.py b/tests/test_autosummary.py
index 7783cc7b..048940d0 100644
--- a/tests/test_autosummary.py
+++ b/tests/test_autosummary.py
@@ -23,6 +23,14 @@ def test_mangle_signature():
:: (a, b[, aaa, bbb, ccc, ...])
(a, b, c=(), d=<foo>) :: (a, b[, c, d])
(a, b, c='foobar()', d=123) :: (a, b[, c, d])
+ (a, b[, c]) :: (a, b[, c])
+ (a, b[, cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]) :: (a, b[, ...)
+ (a, b='c=d, e=f, g=h', c=3) :: (a[, b, c])
+ (a, b='c=d, \\'e=f,\\' g=h', c=3) :: (a[, b, c])
+ (a, b='c=d, ', e='\\\\' g=h, c=3) :: (a[, b, e, c])
+ (a, b={'c=d, ': 3, '\\\\': 3}) :: (a[, b])
+ (a=1, b=2, c=3) :: ([a, b, c])
+ (a=1, b=<SomeClass: a, b, c>, c=3) :: ([a, b, c])
"""
TEST = [map(lambda x: x.strip(), x.split("::")) for x in TEST.split("\n")