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 /sphinx | |
| parent | ec2ac36d5fdec3d52009bcc24b7d3336ee3a9bef (diff) | |
| parent | 09e2e6e04d81d325b9b985fdb2a4965ffde7a24c (diff) | |
| download | sphinx-50bbb1a5e764ad72879f1ce5a6ddbdcfba5cfe08.tar.gz | |
Merged in jonwaltman/sphinx-info (pull request #5)
Diffstat (limited to 'sphinx')
| -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 |
6 files changed, 126 insertions, 39 deletions
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: |
