summaryrefslogtreecommitdiff
path: root/sphinx
diff options
context:
space:
mode:
authorJon Waltman <jonathan.waltman@gmail.com>2013-01-05 08:48:42 -0600
committerJon Waltman <jonathan.waltman@gmail.com>2013-01-05 08:48:42 -0600
commitfdbeef5cd3c9aef4539c722ebc272c8d7fec8a08 (patch)
tree4eb1315b105d733eea7e1a6573ba326241300280 /sphinx
parent597d394a129fc0aef71de66d6abea426c9804638 (diff)
parent5ab9a2eec106ba1125b92856f86de11b4fe906fc (diff)
downloadsphinx-fdbeef5cd3c9aef4539c722ebc272c8d7fec8a08.tar.gz
Merged in rolmei/sphinx-epub (pull request #103: Whitespace cleanup)
Diffstat (limited to 'sphinx')
-rw-r--r--sphinx/application.py74
-rw-r--r--sphinx/builders/__init__.py10
-rw-r--r--sphinx/cmdline.py49
-rw-r--r--sphinx/environment.py1
-rw-r--r--sphinx/ext/autodoc.py30
-rw-r--r--sphinx/util/__init__.py6
6 files changed, 132 insertions, 38 deletions
diff --git a/sphinx/application.py b/sphinx/application.py
index 6eefc3e4..7e07f6b9 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -61,7 +61,8 @@ class Sphinx(object):
def __init__(self, srcdir, confdir, outdir, doctreedir, buildername,
confoverrides=None, status=sys.stdout, warning=sys.stderr,
- freshenv=False, warningiserror=False, tags=None):
+ freshenv=False, warningiserror=False, tags=None, verbosity=0):
+ self.verbosity = verbosity
self.next_listener_id = 0
self._extensions = {}
self._listeners = {}
@@ -214,6 +215,17 @@ class Sphinx(object):
self.emit('build-finished', None)
self.builder.cleanup()
+ def _log(self, message, wfile, nonl=False):
+ try:
+ wfile.write(message)
+ except UnicodeEncodeError:
+ encoding = getattr(wfile, 'encoding', 'ascii') or 'ascii'
+ wfile.write(message.encode(encoding, 'replace'))
+ if not nonl:
+ wfile.write('\n')
+ if hasattr(wfile, 'flush'):
+ wfile.flush()
+
def warn(self, message, location=None, prefix='WARNING: '):
if isinstance(location, tuple):
docname, lineno = location
@@ -226,26 +238,30 @@ class Sphinx(object):
if self.warningiserror:
raise SphinxWarning(warntext)
self._warncount += 1
- try:
- self._warning.write(warntext)
- except UnicodeEncodeError:
- encoding = getattr(self._warning, 'encoding', 'ascii') or 'ascii'
- self._warning.write(warntext.encode(encoding, 'replace'))
+ self._log(warntext, self._warning, True)
def info(self, message='', nonl=False):
- try:
- self._status.write(message)
- except UnicodeEncodeError:
- encoding = getattr(self._status, 'encoding', 'ascii') or 'ascii'
- self._status.write(message.encode(encoding, 'replace'))
- if not nonl:
- self._status.write('\n')
- self._status.flush()
+ self._log(message, self._status, nonl)
+
+ def verbose(self, message, *args, **kwargs):
+ if self.verbosity < 1:
+ return
+ if args or kwargs:
+ message = message % (args or kwargs)
+ self._log(message, self._warning)
+
+ def debug(self, message, *args, **kwargs):
+ if self.verbosity < 2:
+ return
+ if args or kwargs:
+ message = message % (args or kwargs)
+ self._log(message, self._warning)
# general extensibility interface
def setup_extension(self, extension):
"""Import and setup a Sphinx extension module. No-op if called twice."""
+ self.debug('setting up extension: %r', extension)
if extension in self._extensions:
return
try:
@@ -306,9 +322,12 @@ class Sphinx(object):
else:
self._listeners[event][listener_id] = callback
self.next_listener_id += 1
+ self.debug('connecting event %r: %r [id=%s]',
+ event, callback, listener_id)
return listener_id
def disconnect(self, listener_id):
+ self.debug('disconnecting event: [id=%s]', listener_id)
for event in self._listeners.itervalues():
event.pop(listener_id, None)
@@ -328,6 +347,7 @@ class Sphinx(object):
# registering addon parts
def add_builder(self, builder):
+ self.debug('adding builder: %r', builder)
if not hasattr(builder, 'name'):
raise ExtensionError('Builder class %s has no "name" attribute'
% builder)
@@ -342,6 +362,7 @@ class Sphinx(object):
self.builderclasses[builder.name] = builder
def add_config_value(self, name, default, rebuild):
+ self.debug('adding config value: %r', (name, default, rebuild))
if name in self.config.values:
raise ExtensionError('Config value %r already present' % name)
if rebuild in (False, True):
@@ -349,11 +370,13 @@ class Sphinx(object):
self.config.values[name] = (default, rebuild)
def add_event(self, name):
+ self.debug('adding event: %r', name)
if name in self._events:
raise ExtensionError('Event %r already present' % name)
self._events[name] = ''
def add_node(self, node, **kwds):
+ self.debug('adding node: %r', (node, kwds))
nodes._add_node_class_names([node.__name__])
for key, val in kwds.iteritems():
try:
@@ -393,24 +416,30 @@ class Sphinx(object):
return obj
def add_directive(self, name, obj, content=None, arguments=None, **options):
+ self.debug('adding directive: %r',
+ (name, obj, content, arguments, options))
directives.register_directive(
name, self._directive_helper(obj, content, arguments, **options))
def add_role(self, name, role):
+ self.debug('adding role: %r', (name, role))
roles.register_local_role(name, role)
def add_generic_role(self, name, nodeclass):
# don't use roles.register_generic_role because it uses
# register_canonical_role
+ self.debug('adding generic role: %r', (name, nodeclass))
role = roles.GenericRole(name, nodeclass)
roles.register_local_role(name, role)
def add_domain(self, domain):
+ self.debug('adding domain: %r', domain)
if domain.name in self.domains:
raise ExtensionError('domain %s already registered' % domain.name)
self.domains[domain.name] = domain
def override_domain(self, domain):
+ self.debug('overriding domain: %r', domain)
if domain.name not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain.name)
if not issubclass(domain, self.domains[domain.name]):
@@ -420,17 +449,21 @@ class Sphinx(object):
def add_directive_to_domain(self, domain, name, obj,
content=None, arguments=None, **options):
+ self.debug('adding directive to domain: %r',
+ (domain, name, obj, content, arguments, options))
if domain not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].directives[name] = \
self._directive_helper(obj, content, arguments, **options)
def add_role_to_domain(self, domain, name, role):
+ self.debug('adding role to domain: %r', (domain, name, role))
if domain not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].roles[name] = role
def add_index_to_domain(self, domain, index):
+ self.debug('adding index to domain: %r', (domain, index))
if domain not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].indices.append(index)
@@ -438,6 +471,9 @@ class Sphinx(object):
def add_object_type(self, directivename, rolename, indextemplate='',
parse_node=None, ref_nodeclass=None, objname='',
doc_field_types=[]):
+ self.debug('adding object type: %r',
+ (directivename, rolename, indextemplate, parse_node,
+ ref_nodeclass, objname, doc_field_types))
StandardDomain.object_types[directivename] = \
ObjType(objname or directivename, rolename)
# create a subclass of GenericObject as the new directive
@@ -454,6 +490,9 @@ class Sphinx(object):
def add_crossref_type(self, directivename, rolename, indextemplate='',
ref_nodeclass=None, objname=''):
+ self.debug('adding crossref type: %r',
+ (directivename, rolename, indextemplate, ref_nodeclass,
+ objname))
StandardDomain.object_types[directivename] = \
ObjType(objname or directivename, rolename)
# create a subclass of Target as the new directive
@@ -464,9 +503,11 @@ class Sphinx(object):
StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass)
def add_transform(self, transform):
+ self.debug('adding transform: %r', transform)
SphinxStandaloneReader.transforms.append(transform)
def add_javascript(self, filename):
+ self.debug('adding javascript: %r', filename)
from sphinx.builders.html import StandaloneHTMLBuilder
if '://' in filename:
StandaloneHTMLBuilder.script_files.append(filename)
@@ -475,6 +516,7 @@ class Sphinx(object):
posixpath.join('_static', filename))
def add_stylesheet(self, filename):
+ self.debug('adding stylesheet: %r', filename)
from sphinx.builders.html import StandaloneHTMLBuilder
if '://' in filename:
StandaloneHTMLBuilder.css_files.append(filename)
@@ -483,21 +525,25 @@ class Sphinx(object):
posixpath.join('_static', filename))
def add_lexer(self, alias, lexer):
+ self.debug('adding lexer: %r', (alias, lexer))
from sphinx.highlighting import lexers
if lexers is None:
return
lexers[alias] = lexer
def add_autodocumenter(self, cls):
+ self.debug('adding autodocumenter: %r', cls)
from sphinx.ext import autodoc
autodoc.add_documenter(cls)
self.add_directive('auto' + cls.objtype, autodoc.AutoDirective)
def add_autodoc_attrgetter(self, type, getter):
+ self.debug('adding autodoc attrgetter: %r', (type, getter))
from sphinx.ext import autodoc
autodoc.AutoDirective._special_attrgetters[type] = getter
def add_search_language(self, cls):
+ self.debug('adding search language: %r', cls)
from sphinx.search import languages, SearchLanguage
assert isinstance(cls, SearchLanguage)
languages[cls.lang] = cls
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index 9a869aa9..97932c4c 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -119,9 +119,13 @@ class Builder(object):
summary = bold(summary)
for item in iterable:
l += 1
- self.info(term_width_line('%s[%3d%%] %s' %
- (summary, 100*l/length,
- colorfunc(item))), nonl=1)
+ s = '%s[%3d%%] %s' % (summary, 100*l/length,
+ colorfunc(item))
+ if self.app.verbosity:
+ s += '\n'
+ else:
+ s = term_width_line(s)
+ self.info(s, nonl=1)
yield item
if l > 0:
self.info()
diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py
index 20ee536b..0a1cab7d 100644
--- a/sphinx/cmdline.py
+++ b/sphinx/cmdline.py
@@ -59,6 +59,10 @@ new and changed files
-w <file> -- write warnings (and errors) to given file
-W -- turn warnings into errors
-P -- run Pdb on exception
+ -T -- show full traceback on exception
+ -v -- increase verbosity (can be repeated)
+ --help -- show this help and exit
+ --version -- show version information and exit
Modi:
* without -a and without filenames, write new and changed files.
* with -a, write all files.
@@ -71,8 +75,15 @@ def main(argv):
nocolor()
try:
- opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:ng:NEqQWw:P')
+ opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:ng:NEqQWw:PThv',
+ ['help', 'version'])
allopts = set(opt[0] for opt in opts)
+ if '-h' in allopts or '--help' in allopts:
+ usage(argv)
+ return 0
+ if '--version' in allopts:
+ print 'Sphinx (sphinx-build) %s' % __version__
+ return 0
srcdir = confdir = abspath(args[0])
if not path.isdir(srcdir):
print >>sys.stderr, 'Error: Cannot find source directory `%s\'.' % (
@@ -87,15 +98,18 @@ def main(argv):
if not path.isdir(outdir):
print >>sys.stderr, 'Making output directory...'
os.makedirs(outdir)
- except (IndexError, getopt.error):
- usage(argv)
+ except getopt.error, err:
+ usage(argv, 'Error: %s' % err)
+ return 1
+ except IndexError:
+ usage(argv, 'Error: Insufficient arguments.')
return 1
filenames = args[2:]
err = 0
for filename in filenames:
if not path.isfile(filename):
- print >>sys.stderr, 'Cannot find file %r.' % filename
+ print >>sys.stderr, 'Error: Cannot find file %r.' % filename
err = 1
if err:
return 1
@@ -109,6 +123,8 @@ def main(argv):
buildername = None
force_all = freshenv = warningiserror = use_pdb = False
+ show_traceback = False
+ verbosity = 0
status = sys.stdout
warning = sys.stderr
error = sys.stderr
@@ -121,7 +137,7 @@ def main(argv):
buildername = val
elif opt == '-a':
if filenames:
- usage(argv, 'Cannot combine -a option and filenames.')
+ usage(argv, 'Error: Cannot combine -a option and filenames.')
return 1
force_all = True
elif opt == '-t':
@@ -185,6 +201,11 @@ def main(argv):
warnfile = val
elif opt == '-P':
use_pdb = True
+ elif opt == '-T':
+ show_traceback = True
+ elif opt == '-v':
+ verbosity += 1
+ show_traceback = True
if warning and warnfile:
warnfp = open(warnfile, 'w')
@@ -194,17 +215,10 @@ def main(argv):
try:
app = Sphinx(srcdir, confdir, outdir, doctreedir, buildername,
confoverrides, status, warning, freshenv,
- warningiserror, tags)
+ warningiserror, tags, verbosity)
app.build(force_all, filenames)
return app.statuscode
- except KeyboardInterrupt:
- if use_pdb:
- import pdb
- print >>error, red('Interrupted while building, starting debugger:')
- traceback.print_exc()
- pdb.post_mortem(sys.exc_info()[2])
- return 1
- except Exception, err:
+ except (Exception, KeyboardInterrupt), err:
if use_pdb:
import pdb
print >>error, red('Exception occurred while building, '
@@ -213,7 +227,12 @@ def main(argv):
pdb.post_mortem(sys.exc_info()[2])
else:
print >>error
- if isinstance(err, SystemMessage):
+ if show_traceback:
+ traceback.print_exc(None, error)
+ print >>error
+ if isinstance(err, KeyboardInterrupt):
+ print >>error, 'interrupted!'
+ elif isinstance(err, SystemMessage):
print >>error, red('reST markup error:')
print >>error, terminal_safe(err.args[0])
elif isinstance(err, SphinxError):
diff --git a/sphinx/environment.py b/sphinx/environment.py
index 4f9c30c6..5b166812 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -951,6 +951,7 @@ class BuildEnvironment:
filterlevel = self.config.keep_warnings and 2 or 5
for node in doctree.traverse(nodes.system_message):
if node['level'] < filterlevel:
+ self.app.debug('%s [filtered system message]', node.astext())
node.parent.remove(node)
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index d17800b0..300c4f22 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -317,13 +317,20 @@ class Documenter(object):
Returns True if successful, False if an error occurred.
"""
+ if self.objpath:
+ self.env.app.debug('autodoc: from %s import %s',
+ self.modname, '.'.join(self.objpath))
try:
+ self.env.app.debug('autodoc: import %s', self.modname)
__import__(self.modname)
parent = None
obj = self.module = sys.modules[self.modname]
+ self.env.app.debug('autodoc: => %r', obj)
for part in self.objpath:
parent = obj
+ self.env.app.debug('autodoc: getattr(_, %r)', part)
obj = self.get_attr(obj, part)
+ self.env.app.debug('autodoc: => %r', obj)
self.object_name = part
self.parent = parent
self.object = obj
@@ -331,12 +338,16 @@ class Documenter(object):
# this used to only catch SyntaxError, ImportError and AttributeError,
# but importing modules with side effects can raise all kinds of errors
except Exception, err:
- if self.env.app and not self.env.app.quiet:
- self.env.app.info(traceback.format_exc().rstrip())
- self.directive.warn(
- 'autodoc can\'t import/find %s %r, it reported error: '
- '"%s", please check your spelling and sys.path' %
- (self.objtype, str(self.fullname), err))
+ if self.objpath:
+ errmsg = 'autodoc: failed to import %s %r from module %r' % \
+ (self.objtype, '.'.join(self.objpath), self.modname)
+ else:
+ errmsg = 'autodoc: failed to import %s %r' % \
+ (self.objtype, self.fullname)
+ errmsg += '; the following exception was raised:\n%s' % \
+ traceback.format_exc()
+ self.env.app.debug(errmsg)
+ self.directive.warn(errmsg)
self.env.note_reread()
return False
@@ -1294,6 +1305,10 @@ class AutoDirective(Directive):
self.warnings = []
self.result = ViewList()
+ source, lineno = self.reporter.get_source_and_line(self.lineno)
+ self.env.app.debug('%s:%s: <input>\n%s',
+ source, lineno, self.block_text)
+
# find out what documenter to call
objtype = self.name[4:]
doc_class = self._registry[objtype]
@@ -1314,6 +1329,9 @@ class AutoDirective(Directive):
if not self.result:
return self.warnings
+ if self.env.app.verbosity >= 2:
+ self.env.app.debug('autodoc: <output>\n%s', '\n'.join(self.result))
+
# record all filenames as dependencies -- this will at least
# partially make automatic invalidation possible
for fn in self.filename_set:
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index b69b10a9..de4b14a4 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -291,6 +291,12 @@ class Tee(object):
self.stream1.write(text)
self.stream2.write(text)
+ def flush(self):
+ if hasattr(self.stream1, 'flush'):
+ self.stream1.flush()
+ if hasattr(self.stream2, 'flush'):
+ self.stream2.flush()
+
def parselinenos(spec, total):
"""Parse a line number spec (such as "1,2,4-6") and return a list of