diff options
| author | Rob Ruana <rob@relentlessidiot.com> | 2014-01-19 12:31:07 -0500 |
|---|---|---|
| committer | Rob Ruana <rob@relentlessidiot.com> | 2014-01-19 12:31:07 -0500 |
| commit | a8b06aa17015396b9bd5accb5cca4644f69f307d (patch) | |
| tree | d38b9d2e011dccc1a319674799b499b2f31ffece /sphinx | |
| parent | 49b952d84136ef89132de8d48b4b937b816f0c22 (diff) | |
| parent | 2a8cf7c7781a4554adbcb4bae6bec2a40bfc156d (diff) | |
| download | sphinx-a8b06aa17015396b9bd5accb5cca4644f69f307d.tar.gz | |
Merged birkenfeld/sphinx into default
Diffstat (limited to 'sphinx')
29 files changed, 557 insertions, 98 deletions
diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 2551526f..c1e9e38d 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -81,5 +81,11 @@ def main(argv=sys.argv): return cmdline.main(argv) +def make_main(argv=sys.argv): + """Sphinx build "make mode" entry.""" + from sphinx import make_mode + return make_mode.run_make_mode(argv[2:]) + + if __name__ == '__main__': sys.exit(main(sys.argv)) diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py index c3054662..7e95cdae 100644 --- a/sphinx/apidoc.py +++ b/sphinx/apidoc.py @@ -65,7 +65,7 @@ def write_file(name, text, opts): def format_heading(level, text): """Create a heading of <level> [1, 2 or 3 supported].""" - underlining = ['=', '-', '~', ][level-1] * len(text) + underlining = ['=', '-', '~', ][level - 1] * len(text) return '%s\n%s\n\n' % (text, underlining) @@ -173,9 +173,6 @@ def recurse_tree(rootpath, excludes, opts): Look for every file in the directory tree and create the corresponding ReST files. """ - # use absolute path for root, as relative paths like '../../foo' cause - # 'if "/." in root ...' to filter out *all* modules otherwise - rootpath = path.normpath(path.abspath(rootpath)) # check if the base directory is a package and get its name if INITPY in os.listdir(rootpath): root_package = rootpath.split(path.sep)[-1] @@ -185,13 +182,12 @@ def recurse_tree(rootpath, excludes, opts): toplevels = [] followlinks = getattr(opts, 'followlinks', False) + includeprivate = getattr(opts, 'includeprivate', False) for root, subs, files in os.walk(rootpath, followlinks=followlinks): - if is_excluded(root, excludes): - del subs[:] - continue - # document only Python module files + # document only Python module files (that aren't excluded) py_files = sorted(f for f in files - if path.splitext(f)[1] in PY_SUFFIXES) + if path.splitext(f)[1] in PY_SUFFIXES and + not is_excluded(path.join(root, f), excludes)) is_pkg = INITPY in py_files if is_pkg: py_files.remove(INITPY) @@ -200,8 +196,14 @@ def recurse_tree(rootpath, excludes, opts): # only accept non-package at toplevel del subs[:] continue - # remove hidden ('.') and private ('_') directories - subs[:] = sorted(sub for sub in subs if sub[0] not in ['.', '_']) + # remove hidden ('.') and private ('_') directories, as well as + # excluded dirs + if includeprivate: + exclude_prefixes = ('.',) + else: + exclude_prefixes = ('.', '_') + subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) + and not is_excluded(path.join(root, sub), excludes)) if is_pkg: # we are in a package with something to document @@ -225,47 +227,35 @@ def recurse_tree(rootpath, excludes, opts): def normalize_excludes(rootpath, excludes): - """ - Normalize the excluded directory list: - * must be either an absolute path or start with rootpath, - * otherwise it is joined with rootpath - * with trailing slash - """ - f_excludes = [] - for exclude in excludes: - if not path.isabs(exclude) and not exclude.startswith(rootpath): - exclude = path.join(rootpath, exclude) - f_excludes.append(path.normpath(exclude) + path.sep) - return f_excludes + """Normalize the excluded directory list.""" + return [path.normpath(path.abspath(exclude)) for exclude in excludes] def is_excluded(root, excludes): - """ - Check if the directory is in the exclude list. + """Check if the directory is in the exclude list. Note: by having trailing slashes, we avoid common prefix issues, like e.g. an exlude "foo" also accidentally excluding "foobar". """ - sep = path.sep - if not root.endswith(sep): - root += sep + root = path.normpath(root) for exclude in excludes: - if root.startswith(exclude): + if root == exclude: return True return False def main(argv=sys.argv): - """ - Parse and check the command line arguments. - """ + """Parse and check the command line arguments.""" parser = optparse.OptionParser( usage="""\ -usage: %prog [options] -o <output_path> <module_path> [exclude_paths, ...] +usage: %prog [options] -o <output_path> <module_path> [exclude_path, ...] Look recursively in <module_path> for Python modules and packages and create one reST file with automodule directives per package in the <output_path>. +The <exclude_path>s can be files and/or directories that will be excluded +from generation. + Note: By default this script will not overwrite already created files.""") parser.add_option('-o', '--output-dir', action='store', dest='destdir', @@ -327,6 +317,7 @@ Note: By default this script will not overwrite already created files.""") if not path.isdir(opts.destdir): if not opts.dryrun: os.makedirs(opts.destdir) + rootpath = path.normpath(path.abspath(rootpath)) excludes = normalize_excludes(rootpath, excludes) modules = recurse_tree(rootpath, excludes, opts) if opts.full: diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index c153d121..f1280a0b 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -265,6 +265,12 @@ class Builder(object): self.info(bold('no targets are out of date.')) return + # filter "docnames" (list of outdated files) by the updated + # found_docs of the environment; this will remove docs that + # have since been removed + if docnames != ['__all__']: + docnames = set(docnames) & self.env.found_docs + # another indirection to support builders that don't build # files individually self.write(docnames, list(updated_docnames), method) @@ -289,6 +295,7 @@ class Builder(object): docnames = set(build_docnames) | set(updated_docnames) else: docnames = set(build_docnames) + self.app.debug('docnames to write: %s', ', '.join(sorted(docnames))) # add all toctree-containing files that may have changed for docname in list(docnames): diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index b6ebf926..d715607e 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -579,10 +579,7 @@ class StandaloneHTMLBuilder(Builder): # then, copy over all user-supplied static files staticentries = [path.join(self.confdir, spath) for spath in self.config.html_static_path] - matchers = compile_matchers( - self.config.exclude_patterns + - ['**/' + d for d in self.config.exclude_dirnames] - ) + matchers = compile_matchers(self.config.exclude_patterns) for entry in staticentries: if not path.exists(entry): self.warn('html_static_path entry %r does not exist' % entry) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 2d7146c3..fdb47dec 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -42,6 +42,7 @@ General options -d <path> path for the cached environment and doctree files (default: outdir/.doctrees) -j <N> build in parallel with N processes where possible +-M <builder> "make" mode -- used by Makefile, like "sphinx-build -M html" Build configuration options ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,19 +83,28 @@ def main(argv): # Windows' poor cmd box doesn't understand ANSI sequences nocolor() + # parse options try: opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:nNEqQWw:PThvj:', ['help', 'version']) - allopts = set(opt[0] for opt in opts) - if '-h' in allopts or '--help' in allopts: - usage(argv) - print >>sys.stderr - print >>sys.stderr, 'For more information, see '\ - '<http://sphinx-doc.org/>.' - return 0 - if '--version' in allopts: - print 'Sphinx (sphinx-build) %s' % __version__ - return 0 + except getopt.error, err: + usage(argv, 'Error: %s' % err) + return 1 + + # handle basic options + allopts = set(opt[0] for opt in opts) + # help and version options + if '-h' in allopts or '--help' in allopts: + usage(argv) + print >>sys.stderr + print >>sys.stderr, 'For more information, see <http://sphinx-doc.org/>.' + return 0 + if '--version' in allopts: + print 'Sphinx (sphinx-build) %s' % __version__ + return 0 + + # get paths (first and second positional argument) + try: srcdir = confdir = abspath(args[0]) if not path.isdir(srcdir): print >>sys.stderr, 'Error: Cannot find source directory `%s\'.' % ( @@ -103,12 +113,9 @@ def main(argv): if not path.isfile(path.join(srcdir, 'conf.py')) and \ '-c' not in allopts and '-C' not in allopts: print >>sys.stderr, ('Error: Source directory doesn\'t ' - 'contain conf.py file.') + 'contain a conf.py file.') return 1 outdir = abspath(args[1]) - except getopt.error, err: - usage(argv, 'Error: %s' % err) - return 1 except IndexError: usage(argv, 'Error: Insufficient arguments.') return 1 @@ -118,6 +125,7 @@ def main(argv): 'encoding (%r).' % fs_encoding) return 1 + # handle remaining filename arguments filenames = args[2:] err = 0 for filename in filenames: diff --git a/sphinx/config.py b/sphinx/config.py index df74e914..ace5f2a6 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -51,10 +51,6 @@ class Config(object): source_suffix = ('.rst', 'env'), source_encoding = ('utf-8-sig', 'env'), exclude_patterns = ([], 'env'), - # the next three are all deprecated now - unused_docs = ([], 'env'), - exclude_trees = ([], 'env'), - exclude_dirnames = ([], 'env'), default_role = (None, 'env'), add_function_parentheses = (True, 'env'), add_module_names = (True, 'env'), diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 7b1acfd5..6900ea6b 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -58,6 +58,7 @@ class CodeBlock(Directive): 'linenos': directives.flag, 'lineno-start': int, 'emphasize-lines': directives.unchanged_required, + 'filename': directives.unchanged_required, } def run(self): @@ -76,6 +77,9 @@ class CodeBlock(Directive): literal = nodes.literal_block(code, code) literal['language'] = self.arguments[0] + filename = self.options.get('filename') + if filename: + literal['filename'] = filename literal['linenos'] = 'linenos' in self.options or \ 'lineno-start' in self.options extra_args = literal['highlight_args'] = {} @@ -111,6 +115,7 @@ class LiteralInclude(Directive): 'prepend': directives.unchanged_required, 'append': directives.unchanged_required, 'emphasize-lines': directives.unchanged_required, + 'filename': directives.unchanged, } def run(self): @@ -212,6 +217,11 @@ class LiteralInclude(Directive): retnode['language'] = self.options['language'] retnode['linenos'] = 'linenos' in self.options or \ 'lineno-start' in self.options + filename = self.options.get('filename') + if filename is not None: + if not filename: + filename = self.arguments[0] + retnode['filename'] = filename extra_args = retnode['highlight_args'] = {} if hl_lines is not None: extra_args['hl_lines'] = hl_lines diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 377130b8..d44c9cd7 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -537,6 +537,7 @@ class DefinitionParser(object): 'mutable': None, 'const': None, 'typename': None, + 'struct': None, 'unsigned': set(('char', 'short', 'int', 'long')), 'signed': set(('char', 'short', 'int', 'long')), 'short': set(('int',)), diff --git a/sphinx/environment.py b/sphinx/environment.py index a319ef3c..09f76bf2 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -333,9 +333,6 @@ class BuildEnvironment: matchers = compile_matchers( config.exclude_patterns[:] + config.html_extra_path + - config.exclude_trees + - [d + config.source_suffix for d in config.unused_docs] + - ['**/' + d for d in config.exclude_dirnames] + ['**/_sources', '.#*'] ) self.found_docs = set(get_matching_docs( diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 571f36cb..86837ff8 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -70,6 +70,35 @@ class Options(dict): return None +class _MockModule(object): + """Used by autodoc_mock_imports.""" + def __init__(self, *args, **kwargs): + pass + + def __call__(self, *args, **kwargs): + return _MockModule() + + @classmethod + def __getattr__(cls, name): + if name in ('__file__', '__path__'): + return '/dev/null' + elif name[0] == name[0].upper(): + # Not very good, we assume Uppercase names are classes... + mocktype = type(name, (), {}) + mocktype.__module__ = __name__ + return mocktype + else: + return _MockModule() + +def mock_import(modname): + if '.' in modname: + pkg, _n, mods = modname.rpartition('.') + mock_import(pkg) + mod = _MockModule() + sys.modules[modname] = mod + return mod + + ALL = object() INSTANCEATTR = object() @@ -332,6 +361,9 @@ class Documenter(object): self.modname, '.'.join(self.objpath)) try: dbg('[autodoc] import %s', self.modname) + for modname in self.env.config.autodoc_mock_imports: + dbg('[autodoc] adding a mock module %s!', self.modname) + mock_import(modname) __import__(self.modname) parent = None obj = self.module = sys.modules[self.modname] @@ -1453,6 +1485,7 @@ def setup(app): app.add_config_value('autodoc_member_order', 'alphabetic', True) app.add_config_value('autodoc_default_flags', [], True) app.add_config_value('autodoc_docstring_signature', True, True) + app.add_config_value('autodoc_mock_imports', [], True) app.add_event('autodoc-process-docstring') app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index 800e9ca8..32bb96d3 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -178,6 +178,9 @@ def render_dot(self, code, options, format, prefix='graphviz'): if p.returncode != 0: raise GraphvizError('dot exited with error:\n[stderr]\n%s\n' '[stdout]\n%s' % (stderr, stdout)) + if not path.isfile(outfn): + raise GraphvizError('dot did not produce an output file:\n[stderr]\n%s\n' + '[stdout]\n%s' % (stderr, stdout)) return relfn, outfn diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index 2d1d6e30..fd973544 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -154,8 +154,18 @@ class InheritanceGraph(object): nodename = self.class_name(cls, parts) fullname = self.class_name(cls, 0) + # Use first line of docstring as tooltip, if available + tooltip = None + try: + if cls.__doc__: + doc = cls.__doc__.strip().split("\n")[0] + if doc: + tooltip = '"%s"' % doc.replace('"', '\\"') + except Exception: # might raise AttributeError for strange classes + pass + baselist = [] - all_classes[cls] = (nodename, fullname, baselist) + all_classes[cls] = (nodename, fullname, baselist, tooltip) for base in cls.__bases__: if not show_builtins and base in builtins: continue @@ -168,7 +178,7 @@ class InheritanceGraph(object): for cls in classes: recurse(cls) - return all_classes + return all_classes.values() def class_name(self, cls, parts=0): """Given a class object, return a fully-qualified name. @@ -188,7 +198,7 @@ class InheritanceGraph(object): def get_all_class_names(self): """Get all of the class names involved in the graph.""" - return [fullname for (_, fullname, _) in self.class_info.values()] + return [fullname for (_, fullname, _, _) in self.class_info] # These are the default attrs for graphviz default_graph_attrs = { @@ -241,17 +251,13 @@ class InheritanceGraph(object): res.append('digraph %s {\n' % name) res.append(self._format_graph_attrs(g_attrs)) - for cls, (name, fullname, bases) in sorted(self.class_info.items()): + for name, fullname, bases, tooltip in sorted(self.class_info): # Write the node this_node_attrs = n_attrs.copy() if fullname in urls: this_node_attrs['URL'] = '"%s"' % urls[fullname] - # Use first line of docstring as tooltip, if available - if cls.__doc__: - doc = cls.__doc__.strip().split("\n")[0] - if doc: - doc = doc.replace('"', '\\"') - this_node_attrs['tooltip'] = '"%s"' % doc + if tooltip: + this_node_attrs['tooltip'] = tooltip res.append(' "%s" [%s];\n' % (name, self._format_node_attrs(this_node_attrs))) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 962b543b..36fb47d2 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -24,17 +24,17 @@ def doctree_read(app, doctree): def has_tag(modname, fullname, docname): entry = env._viewcode_modules.get(modname, None) - if entry is None: - try: - analyzer = ModuleAnalyzer.for_module(modname) - except Exception: - env._viewcode_modules[modname] = False - return + try: + analyzer = ModuleAnalyzer.for_module(modname) + except Exception: + env._viewcode_modules[modname] = False + return + if not isinstance(analyzer.code, unicode): + code = analyzer.code.decode(analyzer.encoding) + else: + code = analyzer.code + if entry is None or entry[0] != code: analyzer.find_tags() - if not isinstance(analyzer.code, unicode): - code = analyzer.code.decode(analyzer.encoding) - else: - code = analyzer.code entry = code, analyzer.tags, {} env._viewcode_modules[modname] = entry elif entry is False: @@ -142,7 +142,7 @@ def collect_pages(app): if not modnames: return - app.builder.info(' _modules/index') + app.builder.info(' _modules/index', nonl=True) html = ['\n'] # the stack logic is needed for using nested lists for submodules stack = [''] diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py new file mode 100644 index 00000000..24de6b28 --- /dev/null +++ b/sphinx/make_mode.py @@ -0,0 +1,252 @@ +# -*- coding: utf-8 -*- +""" + sphinx.make_mode + ~~~~~~~~~~~~~~~~ + + sphinx-build -M command-line handling. + + This replaces the old, platform-dependent and once-generated content + of Makefile / make.bat. + + This is in its own module so that importing it is fast. It should not + import the main Sphinx modules (like sphinx.applications, sphinx.builders). + + :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import os +import sys +import shutil +from os import path +from subprocess import call + +import sphinx +from sphinx.util.console import bold, blue + +proj_name = os.getenv('SPHINXPROJ', '<project>') + + +BUILDERS = [ + ("", "html", "to make standalone HTML files"), + ("", "dirhtml", "to make HTML files named index.html in directories"), + ("", "singlehtml","to make a single large HTML file"), + ("", "pickle", "to make pickle files"), + ("", "json", "to make JSON files"), + ("", "htmlhelp", "to make HTML files and a HTML help project"), + ("", "qthelp", "to make HTML files and a qthelp project"), + ("", "devhelp", "to make HTML files and a Devhelp project"), + ("", "epub", "to make an epub"), + ("", "latex", "to make LaTeX files, you can set PAPER=a4 or PAPER=letter"), + ("posix", "latexpdf", "to make LaTeX files and run them through pdflatex"), + ("posix", "latexpdfja","to make LaTeX files and run them through platex/dvipdfmx"), + ("", "text", "to make text files"), + ("", "man", "to make manual pages"), + ("", "texinfo", "to make Texinfo files"), + ("posix", "info", "to make Texinfo files and run them through makeinfo"), + ("", "gettext", "to make PO message catalogs"), + ("", "changes", "to make an overview of all changed/added/deprecated items"), + ("", "xml", "to make Docutils-native XML files"), + ("", "pseudoxml", "to make pseudoxml-XML files for display purposes"), + ("", "linkcheck", "to check all external links for integrity"), + ("", "doctest", "to run all doctests embedded in the documentation (if enabled)"), + ("", "coverage", "to run coverage check of the documentation (if enabled)"), +] + + +class Make(object): + + def __init__(self, srcdir, builddir, opts): + self.srcdir = srcdir + self.builddir = builddir + self.opts = opts + + def builddir_join(self, *comps): + return path.join(self.builddir, *comps) + + def build_clean(self): + if not path.exists(self.builddir): + return + elif not path.isdir(self.builddir): + print "Error: %r is not a directory!" % self.builddir + return 1 + print "Removing everything under %r..." % self.builddir + for item in os.listdir(self.builddir): + shutil.rmtree(self.builddir_join(item)) + + def build_help(self): + print bold("Sphinx v%s" % sphinx.__version__) + print "Please use `make %s' where %s is one of" % ((blue('target'),)*2) + for osname, bname, description in BUILDERS: + if not osname or os.name == osname: + print ' %s %s' % (blue(bname.ljust(10)), description) + + def build_html(self): + if self.run_generic_build('html') > 0: + return 1 + print + print 'Build finished. The HTML pages are in %s.' % self.builddir_join('html') + + def build_dirhtml(self): + if self.run_generic_build('dirhtml') > 0: + return 1 + print + print 'Build finished. The HTML pages are in %s.' % self.builddir_join('dirhtml') + + def build_singlehtml(self): + if self.run_generic_build('singlehtml') > 0: + return 1 + print + print 'Build finished. The HTML page is in %s.' % self.builddir_join('singlehtml') + + def build_pickle(self): + if self.run_generic_build('pickle') > 0: + return 1 + print + print 'Build finished; now you can process the pickle files.' + + def build_json(self): + if self.run_generic_build('json') > 0: + return 1 + print + print 'Build finished; now you can process the JSON files.' + + def build_htmlhelp(self): + if self.run_generic_build('htmlhelp') > 0: + return 1 + print + print ('Build finished; now you can run HTML Help Workshop with the ' + '.hhp project file in %s.') % self.builddir_join('htmlhelp') + + def build_qthelp(self): + if self.run_generic_build('qthelp') > 0: + return 1 + print + print ('Build finished; now you can run "qcollectiongenerator" with the ' + '.qhcp project file in %s, like this:') % self.builddir_join('qthelp') + print '$ qcollectiongenerator %s.qhcp' % self.builddir_join('qthelp', proj_name) + print 'To view the help file:' + print '$ assistant -collectionFile %s.qhc' % self.builddir_join('qthelp', proj_name) + + def build_devhelp(self): + if self.run_generic_build('devhelp') > 0: + return 1 + print + print "Build finished." + print "To view the help file:" + print "$ mkdir -p $HOME/.local/share/devhelp/" + proj_name + print "$ ln -s %s $HOME/.local/share/devhelp/%s" % \ + (self.builddir_join('devhelp'), proj_name) + print "$ devhelp" + + def build_epub(self): + if self.run_generic_build('epub') > 0: + return 1 + print + print 'Build finished. The ePub file is in %s.' % self.builddir_join('epub') + + def build_latex(self): + if self.run_generic_build('latex') > 0: + return 1 + print "Build finished; the LaTeX files are in %s." % self.builddir_join('latex') + if os.name == 'posix': + print "Run `make' in that directory to run these through (pdf)latex" + print "(use `make latexpdf' here to do that automatically)." + + def build_latexpdf(self): + if self.run_generic_build('latex') > 0: + return 1 + os.system('make -C %s all-pdf' % self.builddir_join('latex')) + + def build_latexpdfja(self): + if self.run_generic_build('latex') > 0: + return 1 + os.system('make -C %s all-pdf-ja' % self.builddir_join('latex')) + + def build_text(self): + if self.run_generic_build('text') > 0: + return 1 + print + print 'Build finished. The text files are in %s.' % self.builddir_join('text') + + def build_texinfo(self): + if self.run_generic_build('texinfo') > 0: + return 1 + print "Build finished; the Texinfo files are in %s." % self.builddir_join('texinfo') + if os.name == 'posix': + print "Run `make' in that directory to run these through makeinfo" + print "(use `make info' here to do that automatically)." + + def build_info(self): + if self.run_generic_build('texinfo') > 0: + return 1 + os.system('make -C %s info' % self.builddir_join('texinfo')) + + def build_gettext(self): + dtdir = self.builddir_join('gettext', '.doctrees') + if self.run_generic_build('gettext', doctreedir=dtdir) > 0: + return 1 + print + print 'Build finished. The message catalogs are in %s.' % self.builddir_join('gettext') + + def build_changes(self): + if self.run_generic_build('changes') > 0: + return 1 + print + print 'Build finished. The overview file is in %s.' % self.builddir_join('changes') + + def build_linkcheck(self): + res = self.run_generic_build('linkcheck') + print + print ('Link check complete; look for any errors in the above output ' + 'or in %s.') % self.builddir_join('linkcheck', 'output.txt') + return res + + def build_doctest(self): + res = self.run_generic_build('doctest') + print ("Testing of doctests in the sources finished, look at the " + "results in %s." % self.builddir_join('doctest', 'output.txt')) + return res + + def build_coverage(self): + if self.run_generic_build('coverage') > 0: + print "Has the coverage extension been enabled?" + return 1 + print + print ("Testing of coverage in the sources finished, look at the " + "results in %s." % self.builddir_join('coverage')) + + def build_xml(self): + if self.run_generic_build('xml') > 0: + return 1 + print + print 'Build finished. The XML files are in %s.' % self.builddir_join('xml') + + def build_pseudoxml(self): + if self.run_generic_build('pseudoxml') > 0: + return 1 + print + print 'Build finished. The pseudo-XML files are in %s.' % self.builddir_join('pseudoxml') + + def run_generic_build(self, builder, doctreedir=None): + # compatibility with old Makefile + papersize = os.getenv('PAPER', '') + opts = self.opts + if papersize in ('a4', 'letter'): + opts.extend(['-D', 'latex_paper_size=' + papersize]) + if doctreedir is None: + doctreedir = self.builddir_join('doctrees') + return call([sys.executable, sys.argv[0], '-b', builder, + '-d', doctreedir, self.srcdir, self.builddir_join(builder)] + opts) + + +def run_make_mode(args): + if len(args) < 3: + print >>sys.stderr, ('Error: at least 3 arguments (builder, source ' + 'dir, build dir) are required.') + return 1 + make = Make(args[1], args[2], args[3:]) + run_method = 'build_' + args[0] + if hasattr(make, run_method): + return getattr(make, run_method)() + return make.run_generic_build(args[0]) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 3e32f35b..fd358532 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -840,6 +840,76 @@ if "%%1" == "pseudoxml" ( :end ''' +# This will become the Makefile template for Sphinx 1.5. +MAKEFILE_NEW = u'''\ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = %(project_fn)s +SOURCEDIR = %(rsrcdir)s +BUILDDIR = %(rbuilddir)s + +# User-friendly check for sphinx-build. +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error \ +The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx \ +installed, then set the SPHINXBUILD environment variable to point \ +to the full path of the '$(SPHINXBUILD)' executable. Alternatively you \ +can add the directory with the executable to your PATH. \ +If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Has to be explicit, otherwise we don't get "make" without targets right. +help: +\t@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +# You can add custom targets here. + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: +\t@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +''' + +# This will become the make.bat template for Sphinx 1.5. +BATCHFILE_NEW = u'''\ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%%SPHINXBUILD%%" == "" ( +\tset SPHINXBUILD=sphinx-build +) +set BUILDDIR=%(rbuilddir)s +set SPHINXPROJ=%(project_fn)s + +if "%%1" == "" goto help + +%%SPHINXBUILD%% 2> nul +if errorlevel 9009 ( +\techo. +\techo.The 'sphinx-build' command was not found. Make sure you have Sphinx +\techo.installed, then set the SPHINXBUILD environment variable to point +\techo.to the full path of the 'sphinx-build' executable. Alternatively you +\techo.may add the Sphinx directory to PATH. +\techo. +\techo.If you don't have Sphinx installed, grab it from +\techo.http://sphinx-doc.org/ +\texit /b 1 +) + +%%SPHINXBUILD%% -M %%1 %%BUILDDIR%% %%SPHINXOPTS%% +goto end + +:help +%%SPHINXBUILD%% -M help %%BUILDDIR%% %%SPHINXOPTS%% + +:end +''' + def mkdir_p(dir): if path.isdir(dir): diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py index 07cd520c..7999bf59 100644 --- a/sphinx/setup_command.py +++ b/sphinx/setup_command.py @@ -14,6 +14,7 @@ import sys import os +import types from StringIO import StringIO from distutils.cmd import Command @@ -98,6 +99,19 @@ class BuildDoc(Command): return root return None + # Overriding distutils' Command._ensure_stringlike which doesn't support + # unicode, causing finalize_options to fail if invoked again. Workaround + # for http://bugs.python.org/issue19570 + def _ensure_stringlike(self, option, what, default=None): + val = getattr(self, option) + if val is None: + setattr(self, option, default) + return default + elif not isinstance(val, types.StringTypes): + raise DistutilsOptionError("'%s' must be a %s (got `%s`)" + % (option, what, val)) + return val + def finalize_options(self): if self.source_dir is None: self.source_dir = self._guess_source_dir() diff --git a/sphinx/texinputs/Makefile b/sphinx/texinputs/Makefile index 6b87ad88..5e6030c0 100644 --- a/sphinx/texinputs/Makefile +++ b/sphinx/texinputs/Makefile @@ -9,6 +9,10 @@ ARCHIVEPRREFIX = # Additional LaTeX options LATEXOPTS = +LATEX = latex +PDFLATEX = pdflatex +MAKEINDEX = makeindex + all: $(ALLPDF) all-pdf: $(ALLPDF) all-dvi: $(ALLDVI) @@ -43,20 +47,20 @@ bz2: tar # The number of LaTeX runs is quite conservative, but I don't expect it # to get run often, so the little extra time won't hurt. %.dvi: %.tex - latex $(LATEXOPTS) '$<' - latex $(LATEXOPTS) '$<' - latex $(LATEXOPTS) '$<' - -makeindex -s python.ist '$(basename $<).idx' - latex $(LATEXOPTS) '$<' - latex $(LATEXOPTS) '$<' + $(LATEX) $(LATEXOPTS) '$<' + $(LATEX) $(LATEXOPTS) '$<' + $(LATEX) $(LATEXOPTS) '$<' + -$(MAKEINDEX) -s python.ist '$(basename $<).idx' + $(LATEX) $(LATEXOPTS) '$<' + $(LATEX) $(LATEXOPTS) '$<' %.pdf: %.tex - pdflatex $(LATEXOPTS) '$<' - pdflatex $(LATEXOPTS) '$<' - pdflatex $(LATEXOPTS) '$<' - -makeindex -s python.ist '$(basename $<).idx' - pdflatex $(LATEXOPTS) '$<' - pdflatex $(LATEXOPTS) '$<' + $(PDFLATEX) $(LATEXOPTS) '$<' + $(PDFLATEX) $(LATEXOPTS) '$<' + $(PDFLATEX) $(LATEXOPTS) '$<' + -$(MAKEINDEX) -s python.ist '$(basename $<).idx' + $(PDFLATEX) $(LATEXOPTS) '$<' + $(PDFLATEX) $(LATEXOPTS) '$<' clean: rm -f *.dvi *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla diff --git a/sphinx/themes/agogo/static/agogo.css_t b/sphinx/themes/agogo/static/agogo.css_t index 3fb81178..4c7eb378 100644 --- a/sphinx/themes/agogo/static/agogo.css_t +++ b/sphinx/themes/agogo/static/agogo.css_t @@ -462,3 +462,10 @@ div.viewcode-block:target { border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; } + +div.code-block-filename { + background-color: #ddd; + color: #333; + padding: 2px 5px; + font-size: small; +} diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index d54e7f4e..a3255ebd 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -471,6 +471,20 @@ table.highlighttable td { padding: 0 0.5em 0 0.5em; } +div.code-block-filename { + padding: 2px 5px; + font-size: small; +} + +div.code-block-filename tt { + background-color: transparent; +} + +div.code-block-filename + pre, +div.code-block-filename + div.highlight > pre { + margin-top: 0; +} + tt.descname { background-color: transparent; font-weight: bold; diff --git a/sphinx/themes/basic/static/doctools.js b/sphinx/themes/basic/static/doctools.js index 8614442e..2036e5f5 100644 --- a/sphinx/themes/basic/static/doctools.js +++ b/sphinx/themes/basic/static/doctools.js @@ -168,6 +168,9 @@ var Documentation = { var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; if (terms.length) { var body = $('div.body'); + if (!body.length) { + body = $('body'); + } window.setTimeout(function() { $.each(terms, function() { body.highlightText(this.toLowerCase(), 'highlighted'); diff --git a/sphinx/themes/default/static/default.css_t b/sphinx/themes/default/static/default.css_t index 5db77108..cdc1b782 100644 --- a/sphinx/themes/default/static/default.css_t +++ b/sphinx/themes/default/static/default.css_t @@ -308,3 +308,8 @@ div.viewcode-block:target { border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; } + +div.code-block-filename { + color: #efefef; + background-color: #1c4e63; +} diff --git a/sphinx/themes/epub/static/epub.css b/sphinx/themes/epub/static/epub.css index 3f4664f6..6c8ff5e7 100644 --- a/sphinx/themes/epub/static/epub.css +++ b/sphinx/themes/epub/static/epub.css @@ -339,7 +339,7 @@ dl.glossary dt { /* -- code displays --------------------------------------------------------- */ pre { - font-family: "LiberationNarrow", monospace; + font-family: monospace; overflow: auto; overflow-y: hidden; } @@ -360,7 +360,7 @@ table.highlighttable td { } tt { - font-family: "LiberationNarrow", monospace; + font-family: monospace; } tt.descname { @@ -432,6 +432,7 @@ table .link-target { /* -- font-face ------------------------------------------------------------- */ +/* @font-face { font-family: "LiberationNarrow"; font-style: normal; @@ -460,4 +461,4 @@ table .link-target { src: url("res:///Data/fonts/LiberationNarrow-BoldItalic.otf") format("opentype"); } - +*/
\ No newline at end of file diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t index 3c492034..e4f4d2ed 100644 --- a/sphinx/themes/nature/static/nature.css_t +++ b/sphinx/themes/nature/static/nature.css_t @@ -243,3 +243,9 @@ div.viewcode-block:target { border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; } + +div.code-block-filename { + background-color: #ddd; + color: #222; + border: 1px solid #C6C9CB; +} diff --git a/sphinx/themes/pyramid/static/pyramid.css_t b/sphinx/themes/pyramid/static/pyramid.css_t index c4e94908..c724a493 100644 --- a/sphinx/themes/pyramid/static/pyramid.css_t +++ b/sphinx/themes/pyramid/static/pyramid.css_t @@ -340,3 +340,8 @@ tt.xref { font-weight: normal; font-style: normal; } + +div.code-block-filename { + background-color: #ddd; + color: #222; +} diff --git a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t index af498257..1d7c5796 100644 --- a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +++ b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t @@ -337,3 +337,9 @@ div.viewcode-block:target { border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; } + +div.code-block-filename { + background-color: #ddd; + color: #222; + border: 1px solid #ccc; +} diff --git a/sphinx/themes/traditional/static/traditional.css_t b/sphinx/themes/traditional/static/traditional.css_t index fff411ef..cbea798c 100644 --- a/sphinx/themes/traditional/static/traditional.css_t +++ b/sphinx/themes/traditional/static/traditional.css_t @@ -698,3 +698,7 @@ div.viewcode-block:target { margin: -1px -10px; padding: 0 10px; } + +div.code-block-filename { + background-color: #cceeff; +} diff --git a/sphinx/transforms.py b/sphinx/transforms.py index 35e9d297..e44a3d3e 100644 --- a/sphinx/transforms.py +++ b/sphinx/transforms.py @@ -195,7 +195,10 @@ class Locale(Transform): patch = new_document(source, settings) CustomLocaleReporter(node.source, node.line).set_reporter(patch) parser.parse(msgstr, patch) - patch = patch[0] + try: + patch = patch[0] + except IndexError: # empty node + pass # XXX doctest and other block markup if not isinstance(patch, nodes.paragraph): continue # skip for now @@ -238,8 +241,7 @@ class Locale(Transform): self.document.ids.pop(_id, None) # re-entry with new named section node. - self.document.note_implicit_target( - section_node, section_node) + self.document.note_implicit_target(section_node) # replace target's refname to new target name def is_named_target(node): @@ -298,7 +300,10 @@ class Locale(Transform): patch = new_document(source, settings) CustomLocaleReporter(node.source, node.line).set_reporter(patch) parser.parse(msgstr, patch) - patch = patch[0] + try: + patch = patch[0] + except IndexError: # empty node + pass # XXX doctest and other block markup if not isinstance(patch, nodes.paragraph): continue # skip for now diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index 308e1f5b..61b905f6 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -267,6 +267,9 @@ class HTMLTranslator(BaseTranslator): **highlight_args) starttag = self.starttag(node, 'div', suffix='', CLASS='highlight-%s' % lang) + if node.has_key('filename'): + starttag += '<div class="code-block-filename"><tt>%s</tt></div>' % ( + node['filename'],) self.body.append(starttag + highlighted + '</div>\n') raise nodes.SkipNode diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 5429bcbb..61aa5828 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1337,6 +1337,11 @@ class LaTeXTranslator(nodes.NodeVisitor): highlight_args['force'] = True if 'linenos' in node: linenos = node['linenos'] + filename = node.get('filename') + if filename: + self.body.append('\n{\\colorbox[rgb]{0.9,0.9,0.9}' + '{\\makebox[\\textwidth][l]' + '{\\small\\texttt{%s}}}}\n' % (filename,)) def warner(msg): self.builder.warn(msg, (self.curfilestack[-1], node.line)) hlcode = self.highlighter.highlight_block(code, lang, warn=warner, |
