diff options
author | Georg Brandl <georg@python.org> | 2011-07-07 19:50:11 +0200 |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2011-07-07 19:50:11 +0200 |
commit | 50bbb1a5e764ad72879f1ce5a6ddbdcfba5cfe08 (patch) | |
tree | 6251a2c44945150541824f691d524d5dd7c8bef0 | |
parent | ec2ac36d5fdec3d52009bcc24b7d3336ee3a9bef (diff) | |
parent | 09e2e6e04d81d325b9b985fdb2a4965ffde7a24c (diff) | |
download | sphinx-50bbb1a5e764ad72879f1ce5a6ddbdcfba5cfe08.tar.gz |
Merged in jonwaltman/sphinx-info (pull request #5)
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | LICENSE | 27 | ||||
-rw-r--r-- | doc/ext/autosummary.rst | 14 | ||||
-rw-r--r-- | doc/markup/para.rst | 2 | ||||
-rw-r--r-- | doc/rest.rst | 4 | ||||
-rw-r--r-- | sphinx/builders/gettext.py | 43 | ||||
-rw-r--r-- | sphinx/ext/autosummary/__init__.py | 91 | ||||
-rw-r--r-- | sphinx/ext/autosummary/generate.py | 6 | ||||
-rw-r--r-- | sphinx/ext/mathbase.py | 5 | ||||
-rw-r--r-- | sphinx/themes/basic/static/underscore.js | 7 | ||||
-rw-r--r-- | sphinx/util/nodes.py | 13 | ||||
-rw-r--r-- | tests/root/autosummary.txt | 24 | ||||
-rw-r--r-- | tests/test_autosummary.py | 8 |
13 files changed, 199 insertions, 48 deletions
@@ -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: @@ -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") |