Use sphinx.util.logging instead app.info(), verbose(), debug() and debug2()

This commit is contained in:
Takeshi KOMIYA 2016-12-22 13:41:56 +09:00
parent 70d6a560f2
commit b43523fcbe
23 changed files with 292 additions and 267 deletions

View File

@ -45,7 +45,7 @@ from sphinx.util import logging
from sphinx.util.tags import Tags from sphinx.util.tags import Tags
from sphinx.util.osutil import ENOENT from sphinx.util.osutil import ENOENT
from sphinx.util.console import ( # type: ignore from sphinx.util.console import ( # type: ignore
bold, lightgray, darkgray, darkgreen, term_width_line bold, darkgreen, term_width_line
) )
from sphinx.util.i18n import find_catalog_source_files from sphinx.util.i18n import find_catalog_source_files
@ -164,13 +164,13 @@ class Sphinx(object):
self.messagelog = deque(maxlen=10) # type: deque self.messagelog = deque(maxlen=10) # type: deque
# say hello to the world # say hello to the world
self.info(bold('Running Sphinx v%s' % sphinx.__display_version__)) logger.info(bold('Running Sphinx v%s' % sphinx.__display_version__))
# status code for command-line application # status code for command-line application
self.statuscode = 0 self.statuscode = 0
if not path.isdir(outdir): if not path.isdir(outdir):
self.info('making output directory...') logger.info('making output directory...')
os.makedirs(outdir) os.makedirs(outdir)
# read config # read config
@ -267,8 +267,8 @@ class Sphinx(object):
the configuration. the configuration.
""" """
if self.config.language is not None: if self.config.language is not None:
self.info(bold('loading translations [%s]... ' % logger.info(bold('loading translations [%s]... ' % self.config.language),
self.config.language), nonl=True) nonl=True)
user_locale_dirs = [ user_locale_dirs = [
path.join(self.srcdir, x) for x in self.config.locale_dirs] path.join(self.srcdir, x) for x in self.config.locale_dirs]
# compile mo files if sphinx.po file in user locale directories are updated # compile mo files if sphinx.po file in user locale directories are updated
@ -283,9 +283,9 @@ class Sphinx(object):
if self.config.language is not None: if self.config.language is not None:
if has_translation or self.config.language == 'en': if has_translation or self.config.language == 'en':
# "en" never needs to be translated # "en" never needs to be translated
self.info('done') logger.info('done')
else: else:
self.info('not available for built-in messages') logger.info('not available for built-in messages')
def _init_source_parsers(self): def _init_source_parsers(self):
# type: () -> None # type: () -> None
@ -305,7 +305,7 @@ class Sphinx(object):
self.env.domains[domain] = self.domains[domain](self.env) self.env.domains[domain] = self.domains[domain](self.env)
else: else:
try: try:
self.info(bold('loading pickled environment... '), nonl=True) logger.info(bold('loading pickled environment... '), nonl=True)
self.env = BuildEnvironment.frompickle( self.env = BuildEnvironment.frompickle(
self.srcdir, self.config, path.join(self.doctreedir, ENV_PICKLE_FILENAME)) self.srcdir, self.config, path.join(self.doctreedir, ENV_PICKLE_FILENAME))
self.env.set_warnfunc(self.warn) self.env.set_warnfunc(self.warn)
@ -314,12 +314,12 @@ class Sphinx(object):
for domain in self.domains.keys(): for domain in self.domains.keys():
# this can raise if the data version doesn't fit # this can raise if the data version doesn't fit
self.env.domains[domain] = self.domains[domain](self.env) self.env.domains[domain] = self.domains[domain](self.env)
self.info('done') logger.info('done')
except Exception as err: except Exception as err:
if isinstance(err, IOError) and err.errno == ENOENT: if isinstance(err, IOError) and err.errno == ENOENT:
self.info('not yet created') logger.info('not yet created')
else: else:
self.info('failed: %s' % err) logger.info('failed: %s' % err)
self._init_env(freshenv=True) self._init_env(freshenv=True)
def _init_builder(self, buildername): def _init_builder(self, buildername):
@ -357,11 +357,11 @@ class Sphinx(object):
status = (self.statuscode == 0 and status = (self.statuscode == 0 and
'succeeded' or 'finished with problems') 'succeeded' or 'finished with problems')
if self._warncount: if self._warncount:
self.info(bold('build %s, %s warning%s.' % logger.info(bold('build %s, %s warning%s.' %
(status, self._warncount, (status, self._warncount,
self._warncount != 1 and 's' or ''))) self._warncount != 1 and 's' or '')))
else: else:
self.info(bold('build %s.' % status)) logger.info(bold('build %s.' % status))
except Exception as err: except Exception as err:
# delete the saved env to force a fresh build next time # delete the saved env to force a fresh build next time
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME) envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
@ -374,22 +374,6 @@ class Sphinx(object):
self.builder.cleanup() self.builder.cleanup()
# ---- logging handling ---------------------------------------------------- # ---- logging handling ----------------------------------------------------
def _log(self, message, wfile, nonl=False):
# type: (unicode, IO, bool) -> None
try:
wfile.write(message)
except UnicodeEncodeError:
encoding = getattr(wfile, 'encoding', 'ascii') or 'ascii'
# wfile.write accept only str, not bytes.So, we encode and replace
# non-encodable characters, then decode them.
wfile.write(message.encode(encoding, 'replace').decode(encoding))
if not nonl:
wfile.write('\n')
if hasattr(wfile, 'flush'):
wfile.flush()
self.messagelog.append(message)
def warn(self, message, location=None, prefix=None, def warn(self, message, location=None, prefix=None,
type=None, subtype=None, colorfunc=None): type=None, subtype=None, colorfunc=None):
# type: (unicode, unicode, unicode, unicode, unicode, Callable) -> None # type: (unicode, unicode, unicode, unicode, unicode, Callable) -> None
@ -424,58 +408,25 @@ class Sphinx(object):
If *nonl* is true, don't emit a newline at the end (which implies that If *nonl* is true, don't emit a newline at the end (which implies that
more info output will follow soon.) more info output will follow soon.)
""" """
self._log(message, self._status, nonl) logger.info(message, nonl=nonl)
def verbose(self, message, *args, **kwargs): def verbose(self, message, *args, **kwargs):
# type: (unicode, Any, Any) -> None # type: (unicode, Any, Any) -> None
"""Emit a verbose informational message. """Emit a verbose informational message."""
logger.verbose(message, *args, **kwargs)
The message will only be emitted for verbosity levels >= 1 (i.e. at
least one ``-v`` option was given).
The message can contain %-style interpolation placeholders, which is
formatted with either the ``*args`` or ``**kwargs`` when output.
"""
if self.verbosity < 1:
return
if args or kwargs:
message = message % (args or kwargs)
self._log(message, self._status)
def debug(self, message, *args, **kwargs): def debug(self, message, *args, **kwargs):
# type: (unicode, Any, Any) -> None # type: (unicode, Any, Any) -> None
"""Emit a debug-level informational message. """Emit a debug-level informational message."""
logger.debug(message, *args, **kwargs)
The message will only be emitted for verbosity levels >= 2 (i.e. at
least two ``-v`` options were given).
The message can contain %-style interpolation placeholders, which is
formatted with either the ``*args`` or ``**kwargs`` when output.
"""
if self.verbosity < 2:
return
if args or kwargs:
message = message % (args or kwargs)
self._log(darkgray(message), self._status)
def debug2(self, message, *args, **kwargs): def debug2(self, message, *args, **kwargs):
# type: (unicode, Any, Any) -> None # type: (unicode, Any, Any) -> None
"""Emit a lowlevel debug-level informational message. """Emit a lowlevel debug-level informational message."""
logger.debug2(message, *args, **kwargs)
The message will only be emitted for verbosity level 3 (i.e. three
``-v`` options were given).
The message can contain %-style interpolation placeholders, which is
formatted with either the ``*args`` or ``**kwargs`` when output.
"""
if self.verbosity < 3:
return
if args or kwargs:
message = message % (args or kwargs)
self._log(lightgray(message), self._status)
def _display_chunk(chunk): def _display_chunk(chunk):
# type: (Any) -> unicode # type: (Union[List, Tuple, unicode]) -> unicode
if isinstance(chunk, (list, tuple)): if isinstance(chunk, (list, tuple)):
if len(chunk) == 1: if len(chunk) == 1:
return text_type(chunk[0]) return text_type(chunk[0])
@ -484,21 +435,21 @@ class Sphinx(object):
def old_status_iterator(self, iterable, summary, colorfunc=darkgreen, def old_status_iterator(self, iterable, summary, colorfunc=darkgreen,
stringify_func=_display_chunk): stringify_func=_display_chunk):
# type: (Iterable, unicode, Callable, Callable) -> Iterator # type: (Iterable, unicode, Callable, Callable[[Any], unicode]) -> Iterator
l = 0 l = 0
for item in iterable: for item in iterable:
if l == 0: if l == 0:
self.info(bold(summary), nonl=True) logger.info(bold(summary), nonl=True)
l = 1 l = 1
self.info(colorfunc(stringify_func(item)) + ' ', nonl=True) logger.info(colorfunc(stringify_func(item)) + ' ', nonl=True)
yield item yield item
if l == 1: if l == 1:
self.info() logger.info('')
# new version with progress info # new version with progress info
def status_iterator(self, iterable, summary, colorfunc=darkgreen, length=0, def status_iterator(self, iterable, summary, colorfunc=darkgreen, length=0,
stringify_func=_display_chunk): stringify_func=_display_chunk):
# type: (Iterable, unicode, Callable, int, Callable) -> Iterable # type: (Iterable, unicode, Callable, int, Callable[[Any], unicode]) -> Iterable
if length == 0: if length == 0:
for item in self.old_status_iterator(iterable, summary, colorfunc, for item in self.old_status_iterator(iterable, summary, colorfunc,
stringify_func): stringify_func):
@ -514,17 +465,17 @@ class Sphinx(object):
s += '\n' s += '\n'
else: else:
s = term_width_line(s) s = term_width_line(s)
self.info(s, nonl=True) logger.info(s, nonl=True)
yield item yield item
if l > 0: if l > 0:
self.info() logger.info('')
# ---- general extensibility interface ------------------------------------- # ---- general extensibility interface -------------------------------------
def setup_extension(self, extension): def setup_extension(self, extension):
# type: (unicode) -> None # type: (unicode) -> None
"""Import and setup a Sphinx extension module. No-op if called twice.""" """Import and setup a Sphinx extension module. No-op if called twice."""
self.debug('[app] setting up extension: %r', extension) logger.debug('[app] setting up extension: %r', extension)
if extension in self._extensions: if extension in self._extensions:
return return
if extension in EXTENSION_BLACKLIST: if extension in EXTENSION_BLACKLIST:
@ -536,7 +487,7 @@ class Sphinx(object):
try: try:
mod = __import__(extension, None, None, ['setup']) mod = __import__(extension, None, None, ['setup'])
except ImportError as err: except ImportError as err:
self.verbose('Original exception:\n' + traceback.format_exc()) logger.verbose('Original exception:\n' + traceback.format_exc())
raise ExtensionError('Could not import extension %s' % extension, raise ExtensionError('Could not import extension %s' % extension,
err) err)
if not hasattr(mod, 'setup'): if not hasattr(mod, 'setup'):
@ -596,20 +547,20 @@ class Sphinx(object):
else: else:
self._listeners[event][listener_id] = callback self._listeners[event][listener_id] = callback
self.next_listener_id += 1 self.next_listener_id += 1
self.debug('[app] connecting event %r: %r [id=%s]', logger.debug('[app] connecting event %r: %r [id=%s]',
event, callback, listener_id) event, callback, listener_id)
return listener_id return listener_id
def disconnect(self, listener_id): def disconnect(self, listener_id):
# type: (int) -> None # type: (int) -> None
self.debug('[app] disconnecting event: [id=%s]', listener_id) logger.debug('[app] disconnecting event: [id=%s]', listener_id)
for event in itervalues(self._listeners): for event in itervalues(self._listeners):
event.pop(listener_id, None) event.pop(listener_id, None)
def emit(self, event, *args): def emit(self, event, *args):
# type: (unicode, Any) -> List # type: (unicode, Any) -> List
try: try:
self.debug2('[app] emitting event: %r%s', event, repr(args)[:100]) logger.debug2('[app] emitting event: %r%s', event, repr(args)[:100])
except Exception: except Exception:
# not every object likes to be repr()'d (think # not every object likes to be repr()'d (think
# random stuff coming via autodoc) # random stuff coming via autodoc)
@ -631,7 +582,7 @@ class Sphinx(object):
def add_builder(self, builder): def add_builder(self, builder):
# type: (Type[Builder]) -> None # type: (Type[Builder]) -> None
self.debug('[app] adding builder: %r', builder) logger.debug('[app] adding builder: %r', builder)
if not hasattr(builder, 'name'): if not hasattr(builder, 'name'):
raise ExtensionError('Builder class %s has no "name" attribute' raise ExtensionError('Builder class %s has no "name" attribute'
% builder) % builder)
@ -643,7 +594,7 @@ class Sphinx(object):
def add_config_value(self, name, default, rebuild, types=()): def add_config_value(self, name, default, rebuild, types=()):
# type: (unicode, Any, Union[bool, unicode], Any) -> None # type: (unicode, Any, Union[bool, unicode], Any) -> None
self.debug('[app] adding config value: %r', logger.debug('[app] adding config value: %r',
(name, default, rebuild) + ((types,) if types else ())) # type: ignore (name, default, rebuild) + ((types,) if types else ())) # type: ignore
if name in self.config.values: if name in self.config.values:
raise ExtensionError('Config value %r already present' % name) raise ExtensionError('Config value %r already present' % name)
@ -653,19 +604,19 @@ class Sphinx(object):
def add_event(self, name): def add_event(self, name):
# type: (unicode) -> None # type: (unicode) -> None
self.debug('[app] adding event: %r', name) logger.debug('[app] adding event: %r', name)
if name in self._events: if name in self._events:
raise ExtensionError('Event %r already present' % name) raise ExtensionError('Event %r already present' % name)
self._events[name] = '' self._events[name] = ''
def set_translator(self, name, translator_class): def set_translator(self, name, translator_class):
# type: (unicode, Any) -> None # type: (unicode, Any) -> None
self.info(bold('A Translator for the %s builder is changed.' % name)) logger.info(bold('A Translator for the %s builder is changed.' % name))
self._translators[name] = translator_class self._translators[name] = translator_class
def add_node(self, node, **kwds): def add_node(self, node, **kwds):
# type: (nodes.Node, Any) -> None # type: (nodes.Node, Any) -> None
self.debug('[app] adding node: %r', (node, kwds)) logger.debug('[app] adding node: %r', (node, kwds))
if not kwds.pop('override', False) and \ if not kwds.pop('override', False) and \
hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__): hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__):
logger.warning('while setting up extension %s: node class %r is ' logger.warning('while setting up extension %s: node class %r is '
@ -719,7 +670,7 @@ class Sphinx(object):
def add_directive(self, name, obj, content=None, arguments=None, **options): def add_directive(self, name, obj, content=None, arguments=None, **options):
# type: (unicode, Any, unicode, Any, Any) -> None # type: (unicode, Any, unicode, Any, Any) -> None
self.debug('[app] adding directive: %r', logger.debug('[app] adding directive: %r',
(name, obj, content, arguments, options)) (name, obj, content, arguments, options))
if name in directives._directives: if name in directives._directives:
logger.warning('while setting up extension %s: directive %r is ' logger.warning('while setting up extension %s: directive %r is '
@ -731,7 +682,7 @@ class Sphinx(object):
def add_role(self, name, role): def add_role(self, name, role):
# type: (unicode, Any) -> None # type: (unicode, Any) -> None
self.debug('[app] adding role: %r', (name, role)) logger.debug('[app] adding role: %r', (name, role))
if name in roles._roles: if name in roles._roles:
logger.warning('while setting up extension %s: role %r is ' logger.warning('while setting up extension %s: role %r is '
'already registered, it will be overridden', 'already registered, it will be overridden',
@ -743,7 +694,7 @@ class Sphinx(object):
# type: (unicode, Any) -> None # type: (unicode, Any) -> None
# don't use roles.register_generic_role because it uses # don't use roles.register_generic_role because it uses
# register_canonical_role # register_canonical_role
self.debug('[app] adding generic role: %r', (name, nodeclass)) logger.debug('[app] adding generic role: %r', (name, nodeclass))
if name in roles._roles: if name in roles._roles:
logger.warning('while setting up extension %s: role %r is ' logger.warning('while setting up extension %s: role %r is '
'already registered, it will be overridden', 'already registered, it will be overridden',
@ -754,14 +705,14 @@ class Sphinx(object):
def add_domain(self, domain): def add_domain(self, domain):
# type: (Type[Domain]) -> None # type: (Type[Domain]) -> None
self.debug('[app] adding domain: %r', domain) logger.debug('[app] adding domain: %r', domain)
if domain.name in self.domains: if domain.name in self.domains:
raise ExtensionError('domain %s already registered' % domain.name) raise ExtensionError('domain %s already registered' % domain.name)
self.domains[domain.name] = domain self.domains[domain.name] = domain
def override_domain(self, domain): def override_domain(self, domain):
# type: (Type[Domain]) -> None # type: (Type[Domain]) -> None
self.debug('[app] overriding domain: %r', domain) logger.debug('[app] overriding domain: %r', domain)
if domain.name not in self.domains: if domain.name not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain.name) raise ExtensionError('domain %s not yet registered' % domain.name)
if not issubclass(domain, self.domains[domain.name]): if not issubclass(domain, self.domains[domain.name]):
@ -772,7 +723,7 @@ class Sphinx(object):
def add_directive_to_domain(self, domain, name, obj, def add_directive_to_domain(self, domain, name, obj,
content=None, arguments=None, **options): content=None, arguments=None, **options):
# type: (unicode, unicode, Any, unicode, Any, Any) -> None # type: (unicode, unicode, Any, unicode, Any, Any) -> None
self.debug('[app] adding directive to domain: %r', logger.debug('[app] adding directive to domain: %r',
(domain, name, obj, content, arguments, options)) (domain, name, obj, content, arguments, options))
if domain not in self.domains: if domain not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain) raise ExtensionError('domain %s not yet registered' % domain)
@ -781,14 +732,14 @@ class Sphinx(object):
def add_role_to_domain(self, domain, name, role): def add_role_to_domain(self, domain, name, role):
# type: (unicode, unicode, Any) -> None # type: (unicode, unicode, Any) -> None
self.debug('[app] adding role to domain: %r', (domain, name, role)) logger.debug('[app] adding role to domain: %r', (domain, name, role))
if domain not in self.domains: if domain not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain) raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].roles[name] = role self.domains[domain].roles[name] = role
def add_index_to_domain(self, domain, index): def add_index_to_domain(self, domain, index):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
self.debug('[app] adding index to domain: %r', (domain, index)) logger.debug('[app] adding index to domain: %r', (domain, index))
if domain not in self.domains: if domain not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain) raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].indices.append(index) self.domains[domain].indices.append(index)
@ -797,7 +748,7 @@ class Sphinx(object):
parse_node=None, ref_nodeclass=None, objname='', parse_node=None, ref_nodeclass=None, objname='',
doc_field_types=[]): doc_field_types=[]):
# type: (unicode, unicode, unicode, Callable, nodes.Node, unicode, List) -> None # type: (unicode, unicode, unicode, Callable, nodes.Node, unicode, List) -> None
self.debug('[app] adding object type: %r', logger.debug('[app] adding object type: %r',
(directivename, rolename, indextemplate, parse_node, (directivename, rolename, indextemplate, parse_node,
ref_nodeclass, objname, doc_field_types)) ref_nodeclass, objname, doc_field_types))
StandardDomain.object_types[directivename] = \ StandardDomain.object_types[directivename] = \
@ -817,7 +768,7 @@ class Sphinx(object):
def add_crossref_type(self, directivename, rolename, indextemplate='', def add_crossref_type(self, directivename, rolename, indextemplate='',
ref_nodeclass=None, objname=''): ref_nodeclass=None, objname=''):
# type: (unicode, unicode, unicode, nodes.Node, unicode) -> None # type: (unicode, unicode, unicode, nodes.Node, unicode) -> None
self.debug('[app] adding crossref type: %r', logger.debug('[app] adding crossref type: %r',
(directivename, rolename, indextemplate, ref_nodeclass, (directivename, rolename, indextemplate, ref_nodeclass,
objname)) objname))
StandardDomain.object_types[directivename] = \ StandardDomain.object_types[directivename] = \
@ -831,12 +782,12 @@ class Sphinx(object):
def add_transform(self, transform): def add_transform(self, transform):
# type: (Transform) -> None # type: (Transform) -> None
self.debug('[app] adding transform: %r', transform) logger.debug('[app] adding transform: %r', transform)
SphinxStandaloneReader.transforms.append(transform) SphinxStandaloneReader.transforms.append(transform)
def add_javascript(self, filename): def add_javascript(self, filename):
# type: (unicode) -> None # type: (unicode) -> None
self.debug('[app] adding javascript: %r', filename) logger.debug('[app] adding javascript: %r', filename)
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
if '://' in filename: if '://' in filename:
StandaloneHTMLBuilder.script_files.append(filename) StandaloneHTMLBuilder.script_files.append(filename)
@ -846,7 +797,7 @@ class Sphinx(object):
def add_stylesheet(self, filename): def add_stylesheet(self, filename):
# type: (unicode) -> None # type: (unicode) -> None
self.debug('[app] adding stylesheet: %r', filename) logger.debug('[app] adding stylesheet: %r', filename)
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
if '://' in filename: if '://' in filename:
StandaloneHTMLBuilder.css_files.append(filename) StandaloneHTMLBuilder.css_files.append(filename)
@ -856,12 +807,12 @@ class Sphinx(object):
def add_latex_package(self, packagename, options=None): def add_latex_package(self, packagename, options=None):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
self.debug('[app] adding latex package: %r', packagename) logger.debug('[app] adding latex package: %r', packagename)
self.builder.usepackages.append((packagename, options)) self.builder.usepackages.append((packagename, options))
def add_lexer(self, alias, lexer): def add_lexer(self, alias, lexer):
# type: (unicode, Any) -> None # type: (unicode, Any) -> None
self.debug('[app] adding lexer: %r', (alias, lexer)) logger.debug('[app] adding lexer: %r', (alias, lexer))
from sphinx.highlighting import lexers from sphinx.highlighting import lexers
if lexers is None: if lexers is None:
return return
@ -869,27 +820,27 @@ class Sphinx(object):
def add_autodocumenter(self, cls): def add_autodocumenter(self, cls):
# type: (Any) -> None # type: (Any) -> None
self.debug('[app] adding autodocumenter: %r', cls) logger.debug('[app] adding autodocumenter: %r', cls)
from sphinx.ext import autodoc from sphinx.ext import autodoc
autodoc.add_documenter(cls) autodoc.add_documenter(cls)
self.add_directive('auto' + cls.objtype, autodoc.AutoDirective) self.add_directive('auto' + cls.objtype, autodoc.AutoDirective)
def add_autodoc_attrgetter(self, type, getter): def add_autodoc_attrgetter(self, type, getter):
# type: (Any, Callable) -> None # type: (Any, Callable) -> None
self.debug('[app] adding autodoc attrgetter: %r', (type, getter)) logger.debug('[app] adding autodoc attrgetter: %r', (type, getter))
from sphinx.ext import autodoc from sphinx.ext import autodoc
autodoc.AutoDirective._special_attrgetters[type] = getter autodoc.AutoDirective._special_attrgetters[type] = getter
def add_search_language(self, cls): def add_search_language(self, cls):
# type: (Any) -> None # type: (Any) -> None
self.debug('[app] adding search language: %r', cls) logger.debug('[app] adding search language: %r', cls)
from sphinx.search import languages, SearchLanguage from sphinx.search import languages, SearchLanguage
assert issubclass(cls, SearchLanguage) assert issubclass(cls, SearchLanguage)
languages[cls.lang] = cls languages[cls.lang] = cls
def add_source_parser(self, suffix, parser): def add_source_parser(self, suffix, parser):
# type: (unicode, Parser) -> None # type: (unicode, Parser) -> None
self.debug('[app] adding search source_parser: %r, %r', suffix, parser) logger.debug('[app] adding search source_parser: %r, %r', suffix, parser)
if suffix in self._additional_source_parsers: if suffix in self._additional_source_parsers:
logger.warning('while setting up extension %s: source_parser for %r is ' logger.warning('while setting up extension %s: source_parser for %r is '
'already registered, it will be overridden', 'already registered, it will be overridden',

View File

@ -40,6 +40,9 @@ if False:
from sphinx.util.tags import Tags # NOQA from sphinx.util.tags import Tags # NOQA
logger = logging.getLogger(__name__)
class Builder(object): class Builder(object):
""" """
Builds target formats from the reST sources. Builds target formats from the reST sources.
@ -180,7 +183,7 @@ class Builder(object):
def cat2relpath(cat): def cat2relpath(cat):
return path.relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP) return path.relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
self.info(bold('building [mo]: ') + message) logger.info(bold('building [mo]: ') + message)
for catalog in self.app.status_iterator( for catalog in self.app.status_iterator(
catalogs, 'writing output... ', darkgreen, len(catalogs), catalogs, 'writing output... ', darkgreen, len(catalogs),
cat2relpath): cat2relpath):
@ -281,7 +284,7 @@ class Builder(object):
First updates the environment, and then calls :meth:`write`. First updates the environment, and then calls :meth:`write`.
""" """
if summary: if summary:
self.info(bold('building [%s]' % self.name) + ': ' + summary) logger.info(bold('building [%s]' % self.name) + ': ' + summary)
# while reading, collect all warnings from docutils # while reading, collect all warnings from docutils
with logging.pending_logging(): with logging.pending_logging():
@ -289,29 +292,29 @@ class Builder(object):
self.doctreedir, self.app)) self.doctreedir, self.app))
doccount = len(updated_docnames) doccount = len(updated_docnames)
self.info(bold('looking for now-outdated files... '), nonl=1) logger.info(bold('looking for now-outdated files... '), nonl=1)
for docname in self.env.check_dependents(updated_docnames): for docname in self.env.check_dependents(updated_docnames):
updated_docnames.add(docname) updated_docnames.add(docname)
outdated = len(updated_docnames) - doccount outdated = len(updated_docnames) - doccount
if outdated: if outdated:
self.info('%d found' % outdated) logger.info('%d found' % outdated)
else: else:
self.info('none found') logger.info('none found')
if updated_docnames: if updated_docnames:
# save the environment # save the environment
from sphinx.application import ENV_PICKLE_FILENAME from sphinx.application import ENV_PICKLE_FILENAME
self.info(bold('pickling environment... '), nonl=True) logger.info(bold('pickling environment... '), nonl=True)
self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME)) self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME))
self.info('done') logger.info('done')
# global actions # global actions
self.info(bold('checking consistency... '), nonl=True) logger.info(bold('checking consistency... '), nonl=True)
self.env.check_consistency() self.env.check_consistency()
self.info('done') logger.info('done')
else: else:
if method == 'update' and not docnames: if method == 'update' and not docnames:
self.info(bold('no targets are out of date.')) logger.info(bold('no targets are out of date.'))
return return
# filter "docnames" (list of outdated files) by the updated # filter "docnames" (list of outdated files) by the updated
@ -358,7 +361,7 @@ class Builder(object):
docnames = set(build_docnames) | set(updated_docnames) docnames = set(build_docnames) | set(updated_docnames)
else: else:
docnames = set(build_docnames) docnames = set(build_docnames)
self.app.debug('docnames to write: %s', ', '.join(sorted(docnames))) logger.debug('docnames to write: %s', ', '.join(sorted(docnames)))
# add all toctree-containing files that may have changed # add all toctree-containing files that may have changed
for docname in list(docnames): for docname in list(docnames):
@ -367,9 +370,9 @@ class Builder(object):
docnames.add(tocdocname) docnames.add(tocdocname)
docnames.add(self.config.master_doc) docnames.add(self.config.master_doc)
self.info(bold('preparing documents... '), nonl=True) logger.info(bold('preparing documents... '), nonl=True)
self.prepare_writing(docnames) self.prepare_writing(docnames)
self.info('done') logger.info('done')
warnings = [] # type: List[Tuple[Tuple, Dict]] warnings = [] # type: List[Tuple[Tuple, Dict]]
if self.parallel_ok: if self.parallel_ok:
@ -425,7 +428,7 @@ class Builder(object):
tasks.add_task(write_process, arg, add_warnings) tasks.add_task(write_process, arg, add_warnings)
# make sure all threads have finished # make sure all threads have finished
self.info(bold('waiting for workers...')) logger.info(bold('waiting for workers...'))
tasks.join() tasks.join()
for warning, kwargs in warnings: for warning, kwargs in warnings:

View File

@ -18,6 +18,7 @@ import shlex
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.config import string_classes from sphinx.config import string_classes
from sphinx.util import logging
from sphinx.util.osutil import copyfile, ensuredir, make_filename from sphinx.util.osutil import copyfile, ensuredir, make_filename
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
from sphinx.util.fileutil import copy_asset from sphinx.util.fileutil import copy_asset
@ -33,6 +34,9 @@ if False:
from typing import Any # NOQA from typing import Any # NOQA
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
# Use plistlib.dump in 3.4 and above # Use plistlib.dump in 3.4 and above
try: try:
write_plist = plistlib.dump # type: ignore write_plist = plistlib.dump # type: ignore
@ -118,13 +122,13 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
target_dir = self.outdir target_dir = self.outdir
if path.isdir(source_dir): if path.isdir(source_dir):
self.info(bold('copying localized files... '), nonl=True) logger.info(bold('copying localized files... '), nonl=True)
excluded = Matcher(self.config.exclude_patterns + ['**/.*']) excluded = Matcher(self.config.exclude_patterns + ['**/.*'])
copy_asset(source_dir, target_dir, excluded, copy_asset(source_dir, target_dir, excluded,
context=self.globalcontext, renderer=self.templates) context=self.globalcontext, renderer=self.templates)
self.info('done') logger.info('done')
def build_helpbook(self): def build_helpbook(self):
# type: () -> None # type: () -> None
@ -165,20 +169,20 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
if self.config.applehelp_remote_url is not None: if self.config.applehelp_remote_url is not None:
info_plist['HPDBookRemoteURL'] = self.config.applehelp_remote_url info_plist['HPDBookRemoteURL'] = self.config.applehelp_remote_url
self.info(bold('writing Info.plist... '), nonl=True) logger.info(bold('writing Info.plist... '), nonl=True)
with open(path.join(contents_dir, 'Info.plist'), 'wb') as f: with open(path.join(contents_dir, 'Info.plist'), 'wb') as f:
write_plist(info_plist, f) write_plist(info_plist, f)
self.info('done') logger.info('done')
# Copy the icon, if one is supplied # Copy the icon, if one is supplied
if self.config.applehelp_icon: if self.config.applehelp_icon:
self.info(bold('copying icon... '), nonl=True) logger.info(bold('copying icon... '), nonl=True)
try: try:
copyfile(path.join(self.srcdir, self.config.applehelp_icon), copyfile(path.join(self.srcdir, self.config.applehelp_icon),
path.join(resources_dir, info_plist['HPDBookIconPath'])) path.join(resources_dir, info_plist['HPDBookIconPath']))
self.info('done') logger.info('done')
except Exception as err: except Exception as err:
self.warn('cannot copy icon file %r: %s' % self.warn('cannot copy icon file %r: %s' %
(path.join(self.srcdir, self.config.applehelp_icon), (path.join(self.srcdir, self.config.applehelp_icon),
@ -186,16 +190,16 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
del info_plist['HPDBookIconPath'] del info_plist['HPDBookIconPath']
# Build the access page # Build the access page
self.info(bold('building access page...'), nonl=True) logger.info(bold('building access page...'), nonl=True)
with codecs.open(path.join(language_dir, '_access.html'), 'w') as f: with codecs.open(path.join(language_dir, '_access.html'), 'w') as f:
f.write(access_page_template % { f.write(access_page_template % {
'toc': htmlescape(toc, quote=True), 'toc': htmlescape(toc, quote=True),
'title': htmlescape(self.config.applehelp_title) 'title': htmlescape(self.config.applehelp_title)
}) })
self.info('done') logger.info('done')
# Generate the help index # Generate the help index
self.info(bold('generating help index... '), nonl=True) logger.info(bold('generating help index... '), nonl=True)
args = [ args = [
self.config.applehelp_indexer_path, self.config.applehelp_indexer_path,
@ -217,7 +221,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
args += ['-l', self.config.applehelp_locale] args += ['-l', self.config.applehelp_locale]
if self.config.applehelp_disable_external_tools: if self.config.applehelp_disable_external_tools:
self.info('skipping') logger.info('skipping')
self.warn('you will need to index this help book with:\n %s' self.warn('you will need to index this help book with:\n %s'
% (' '.join([pipes.quote(arg) for arg in args]))) % (' '.join([pipes.quote(arg) for arg in args])))
@ -232,13 +236,13 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
if p.returncode != 0: if p.returncode != 0:
raise AppleHelpIndexerFailed(output) raise AppleHelpIndexerFailed(output)
else: else:
self.info('done') logger.info('done')
except OSError: except OSError:
raise AppleHelpIndexerFailed('Command not found: %s' % args[0]) raise AppleHelpIndexerFailed('Command not found: %s' % args[0])
# If we've been asked to, sign the bundle # If we've been asked to, sign the bundle
if self.config.applehelp_codesign_identity: if self.config.applehelp_codesign_identity:
self.info(bold('signing help book... '), nonl=True) logger.info(bold('signing help book... '), nonl=True)
args = [ args = [
self.config.applehelp_codesign_path, self.config.applehelp_codesign_path,
@ -251,7 +255,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
args.append(self.bundle_path) args.append(self.bundle_path)
if self.config.applehelp_disable_external_tools: if self.config.applehelp_disable_external_tools:
self.info('skipping') logger.info('skipping')
self.warn('you will need to sign this help book with:\n %s' self.warn('you will need to sign this help book with:\n %s'
% (' '.join([pipes.quote(arg) for arg in args]))) % (' '.join([pipes.quote(arg) for arg in args])))
@ -266,7 +270,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
if p.returncode != 0: if p.returncode != 0:
raise AppleHelpCodeSigningFailed(output) raise AppleHelpCodeSigningFailed(output)
else: else:
self.info('done') logger.info('done')
except OSError: except OSError:
raise AppleHelpCodeSigningFailed('Command not found: %s' % args[0]) raise AppleHelpCodeSigningFailed('Command not found: %s' % args[0])

View File

@ -18,6 +18,7 @@ from sphinx import package_dir
from sphinx.locale import _ from sphinx.locale import _
from sphinx.theming import Theme from sphinx.theming import Theme
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.util import logging
from sphinx.util.osutil import ensuredir, os_path from sphinx.util.osutil import ensuredir, os_path
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
from sphinx.util.fileutil import copy_asset_file from sphinx.util.fileutil import copy_asset_file
@ -29,6 +30,9 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
class ChangesBuilder(Builder): class ChangesBuilder(Builder):
""" """
Write a summary with all versionadded/changed directives. Write a summary with all versionadded/changed directives.
@ -59,9 +63,9 @@ class ChangesBuilder(Builder):
apichanges = [] # type: List[Tuple[unicode, unicode, int]] apichanges = [] # type: List[Tuple[unicode, unicode, int]]
otherchanges = {} # type: Dict[Tuple[unicode, unicode], List[Tuple[unicode, unicode, int]]] # NOQA otherchanges = {} # type: Dict[Tuple[unicode, unicode], List[Tuple[unicode, unicode, int]]] # NOQA
if version not in self.env.versionchanges: if version not in self.env.versionchanges:
self.info(bold('no changes in version %s.' % version)) logger.info(bold('no changes in version %s.' % version))
return return
self.info(bold('writing summary file...')) logger.info(bold('writing summary file...'))
for type, docname, lineno, module, descname, content in \ for type, docname, lineno, module, descname, content in \
self.env.versionchanges[version]: self.env.versionchanges[version]:
if isinstance(descname, tuple): if isinstance(descname, tuple):
@ -125,7 +129,7 @@ class ChangesBuilder(Builder):
break break
return line return line
self.info(bold('copying source files...')) logger.info(bold('copying source files...'))
for docname in self.env.all_docs: for docname in self.env.all_docs:
with codecs.open(self.env.doc2path(docname), 'r', # type: ignore with codecs.open(self.env.doc2path(docname), 'r', # type: ignore
self.env.config.source_encoding) as f: self.env.config.source_encoding) as f:

View File

@ -19,6 +19,7 @@ from os import path
from docutils import nodes from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.util import logging
from sphinx.util.osutil import make_filename from sphinx.util.osutil import make_filename
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
@ -33,6 +34,9 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
class DevhelpBuilder(StandaloneHTMLBuilder): class DevhelpBuilder(StandaloneHTMLBuilder):
""" """
Builder that also outputs GNOME Devhelp file. Builder that also outputs GNOME Devhelp file.
@ -60,7 +64,7 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
def build_devhelp(self, outdir, outname): def build_devhelp(self, outdir, outname):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
self.info('dumping devhelp index...') logger.info('dumping devhelp index...')
# Basic info # Basic info
root = etree.Element('book', root = etree.Element('book',

View File

@ -29,6 +29,7 @@ from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.util import logging
from sphinx.util.osutil import ensuredir, copyfile, make_filename, EEXIST from sphinx.util.osutil import ensuredir, copyfile, make_filename, EEXIST
from sphinx.util.smartypants import sphinx_smarty_pants as ssp from sphinx.util.smartypants import sphinx_smarty_pants as ssp
from sphinx.util.console import brown # type: ignore from sphinx.util.console import brown # type: ignore
@ -39,6 +40,9 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
# (Fragment) templates from which the metainfo files content.opf, toc.ncx, # (Fragment) templates from which the metainfo files content.opf, toc.ncx,
# mimetype, and META-INF/container.xml are created. # mimetype, and META-INF/container.xml are created.
# This template section also defines strings that are embedded in the html # This template section also defines strings that are embedded in the html
@ -547,14 +551,14 @@ class EpubBuilder(StandaloneHTMLBuilder):
def build_mimetype(self, outdir, outname): def build_mimetype(self, outdir, outname):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
"""Write the metainfo file mimetype.""" """Write the metainfo file mimetype."""
self.info('writing %s file...' % outname) logger.info('writing %s file...' % outname)
with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f: # type: ignore with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f: # type: ignore
f.write(self.mimetype_template) f.write(self.mimetype_template)
def build_container(self, outdir, outname): def build_container(self, outdir, outname):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
"""Write the metainfo file META-INF/cointainer.xml.""" """Write the metainfo file META-INF/cointainer.xml."""
self.info('writing %s file...' % outname) logger.info('writing %s file...' % outname)
fn = path.join(outdir, outname) fn = path.join(outdir, outname)
try: try:
os.mkdir(path.dirname(fn)) os.mkdir(path.dirname(fn))
@ -589,7 +593,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
"""Write the metainfo file content.opf It contains bibliographic data, """Write the metainfo file content.opf It contains bibliographic data,
a file list and the spine (the reading order). a file list and the spine (the reading order).
""" """
self.info('writing %s file...' % outname) logger.info('writing %s file...' % outname)
# files # files
if not outdir.endswith(os.sep): if not outdir.endswith(os.sep):
@ -800,7 +804,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
def build_toc(self, outdir, outname): def build_toc(self, outdir, outname):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
"""Write the metainfo file toc.ncx.""" """Write the metainfo file toc.ncx."""
self.info('writing %s file...' % outname) logger.info('writing %s file...' % outname)
if self.config.epub_tocscope == 'default': if self.config.epub_tocscope == 'default':
doctree = self.env.get_and_resolve_doctree(self.config.master_doc, doctree = self.env.get_and_resolve_doctree(self.config.master_doc,
@ -824,7 +828,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
It is a zip file with the mimetype file stored uncompressed as the first It is a zip file with the mimetype file stored uncompressed as the first
entry. entry.
""" """
self.info('writing %s file...' % outname) logger.info('writing %s file...' % outname)
projectfiles = ['META-INF/container.xml', 'content.opf', 'toc.ncx'] # type: List[unicode] # NOQA projectfiles = ['META-INF/container.xml', 'content.opf', 'toc.ncx'] # type: List[unicode] # NOQA
projectfiles.extend(self.files) projectfiles.extend(self.files)
epub = zipfile.ZipFile(path.join(outdir, outname), 'w', # type: ignore epub = zipfile.ZipFile(path.join(outdir, outname), 'w', # type: ignore

View File

@ -16,6 +16,10 @@ from datetime import datetime
from sphinx.config import string_classes from sphinx.config import string_classes
from sphinx.builders.epub import EpubBuilder from sphinx.builders.epub import EpubBuilder
from sphinx.util import logging
logger = logging.getLogger(__name__)
# (Fragment) templates from which the metainfo files content.opf, toc.ncx, # (Fragment) templates from which the metainfo files content.opf, toc.ncx,
@ -235,7 +239,7 @@ class Epub3Builder(EpubBuilder):
def build_navigation_doc(self, outdir, outname): def build_navigation_doc(self, outdir, outname):
"""Write the metainfo file nav.xhtml.""" """Write the metainfo file nav.xhtml."""
self.info('writing %s file...' % outname) logger.info('writing %s file...' % outname)
if self.config.epub_tocscope == 'default': if self.config.epub_tocscope == 'default':
doctree = self.env.get_and_resolve_doctree( doctree = self.env.get_and_resolve_doctree(

View File

@ -21,7 +21,7 @@ from uuid import uuid4
from six import iteritems from six import iteritems
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.util import split_index_msg from sphinx.util import split_index_msg, logging
from sphinx.util.tags import Tags from sphinx.util.tags import Tags
from sphinx.util.nodes import extract_messages, traverse_translatable_index from sphinx.util.nodes import extract_messages, traverse_translatable_index
from sphinx.util.osutil import safe_relpath, ensuredir, canon_path from sphinx.util.osutil import safe_relpath, ensuredir, canon_path
@ -36,6 +36,9 @@ if False:
from sphinx.util.i18n import CatalogInfo # NOQA from sphinx.util.i18n import CatalogInfo # NOQA
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
POHEADER = r""" POHEADER = r"""
# SOME DESCRIPTIVE TITLE. # SOME DESCRIPTIVE TITLE.
# Copyright (C) %(copyright)s # Copyright (C) %(copyright)s
@ -216,8 +219,8 @@ class MessageCatalogBuilder(I18nBuilder):
def _extract_from_template(self): def _extract_from_template(self):
# type: () -> None # type: () -> None
files = self._collect_templates() files = self._collect_templates()
self.info(bold('building [%s]: ' % self.name), nonl=1) logger.info(bold('building [%s]: ' % self.name), nonl=1)
self.info('targets for %d template files' % len(files)) logger.info('targets for %d template files' % len(files))
extract_translations = self.templates.environment.extract_translations extract_translations = self.templates.environment.extract_translations

View File

@ -28,7 +28,7 @@ from docutils.frontend import OptionParser
from docutils.readers.doctree import Reader as DoctreeReader from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import package_dir, __display_version__ from sphinx import package_dir, __display_version__
from sphinx.util import jsonimpl from sphinx.util import jsonimpl, logging
from sphinx.util.i18n import format_date from sphinx.util.i18n import format_date
from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \ from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
movefile, copyfile movefile, copyfile
@ -57,6 +57,8 @@ INVENTORY_FILENAME = 'objects.inv'
#: the filename for the "last build" file (for serializing builders) #: the filename for the "last build" file (for serializing builders)
LAST_BUILD_FILENAME = 'last_build' LAST_BUILD_FILENAME = 'last_build'
logger = logging.getLogger(__name__)
def get_stable_hash(obj): def get_stable_hash(obj):
# type: (Any) -> unicode # type: (Any) -> unicode
@ -502,7 +504,7 @@ class StandaloneHTMLBuilder(Builder):
def gen_indices(self): def gen_indices(self):
# type: () -> None # type: () -> None
self.info(bold('generating indices...'), nonl=1) logger.info(bold('generating indices...'), nonl=1)
# the global general index # the global general index
if self.use_index: if self.use_index:
@ -511,7 +513,7 @@ class StandaloneHTMLBuilder(Builder):
# the global domain-specific indices # the global domain-specific indices
self.write_domain_indices() self.write_domain_indices()
self.info() logger.info('')
def gen_additional_pages(self): def gen_additional_pages(self):
# type: () -> None # type: () -> None
@ -520,25 +522,25 @@ class StandaloneHTMLBuilder(Builder):
for pagename, context, template in pagelist: for pagename, context, template in pagelist:
self.handle_page(pagename, context, template) self.handle_page(pagename, context, template)
self.info(bold('writing additional pages...'), nonl=1) logger.info(bold('writing additional pages...'), nonl=1)
# additional pages from conf.py # additional pages from conf.py
for pagename, template in self.config.html_additional_pages.items(): for pagename, template in self.config.html_additional_pages.items():
self.info(' '+pagename, nonl=1) logger.info(' '+pagename, nonl=1)
self.handle_page(pagename, {}, template) self.handle_page(pagename, {}, template)
# the search page # the search page
if self.search: if self.search:
self.info(' search', nonl=1) logger.info(' search', nonl=1)
self.handle_page('search', {}, 'search.html') self.handle_page('search', {}, 'search.html')
# the opensearch xml file # the opensearch xml file
if self.config.html_use_opensearch and self.search: if self.config.html_use_opensearch and self.search:
self.info(' opensearch', nonl=1) logger.info(' opensearch', nonl=1)
fn = path.join(self.outdir, '_static', 'opensearch.xml') fn = path.join(self.outdir, '_static', 'opensearch.xml')
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn) self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
self.info() logger.info('')
def write_genindex(self): def write_genindex(self):
# type: () -> None # type: () -> None
@ -555,7 +557,7 @@ class StandaloneHTMLBuilder(Builder):
genindexcounts = indexcounts, genindexcounts = indexcounts,
split_index = self.config.html_split_index, split_index = self.config.html_split_index,
) )
self.info(' genindex', nonl=1) logger.info(' genindex', nonl=1)
if self.config.html_split_index: if self.config.html_split_index:
self.handle_page('genindex', genindexcontext, self.handle_page('genindex', genindexcontext,
@ -578,7 +580,7 @@ class StandaloneHTMLBuilder(Builder):
content = content, content = content,
collapse_index = collapse, collapse_index = collapse,
) )
self.info(' ' + indexname, nonl=1) logger.info(' ' + indexname, nonl=1)
self.handle_page(indexname, indexcontext, 'domainindex.html') self.handle_page(indexname, indexcontext, 'domainindex.html')
def copy_image_files(self): def copy_image_files(self):
@ -618,7 +620,7 @@ class StandaloneHTMLBuilder(Builder):
def copy_static_files(self): def copy_static_files(self):
# type: () -> None # type: () -> None
# copy static files # copy static files
self.info(bold('copying static files... '), nonl=True) logger.info(bold('copying static files... '), nonl=True)
ensuredir(path.join(self.outdir, '_static')) ensuredir(path.join(self.outdir, '_static'))
# first, create pygments style file # first, create pygments style file
with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f: with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f:
@ -674,12 +676,12 @@ class StandaloneHTMLBuilder(Builder):
elif not path.isfile(icontarget): elif not path.isfile(icontarget):
copyfile(path.join(self.confdir, self.config.html_favicon), copyfile(path.join(self.confdir, self.config.html_favicon),
icontarget) icontarget)
self.info('done') logger.info('done')
def copy_extra_files(self): def copy_extra_files(self):
# type: () -> None # type: () -> None
# copy html_extra_path files # copy html_extra_path files
self.info(bold('copying extra files... '), nonl=True) logger.info(bold('copying extra files... '), nonl=True)
excluded = Matcher(self.config.exclude_patterns) excluded = Matcher(self.config.exclude_patterns)
for extra_path in self.config.html_extra_path: for extra_path in self.config.html_extra_path:
@ -689,7 +691,7 @@ class StandaloneHTMLBuilder(Builder):
continue continue
copy_asset(entry, self.outdir, excluded) copy_asset(entry, self.outdir, excluded)
self.info('done') logger.info('done')
def write_buildinfo(self): def write_buildinfo(self):
# type: () -> None # type: () -> None
@ -890,7 +892,7 @@ class StandaloneHTMLBuilder(Builder):
def dump_inventory(self): def dump_inventory(self):
# type: () -> None # type: () -> None
self.info(bold('dumping object inventory... '), nonl=True) logger.info(bold('dumping object inventory... '), nonl=True)
with open(path.join(self.outdir, INVENTORY_FILENAME), 'wb') as f: with open(path.join(self.outdir, INVENTORY_FILENAME), 'wb') as f:
f.write((u'# Sphinx inventory version 2\n' f.write((u'# Sphinx inventory version 2\n'
u'# Project: %s\n' u'# Project: %s\n'
@ -913,11 +915,11 @@ class StandaloneHTMLBuilder(Builder):
(u'%s %s:%s %s %s %s\n' % (name, domainname, type, (u'%s %s:%s %s %s %s\n' % (name, domainname, type,
prio, uri, dispname)).encode('utf-8'))) prio, uri, dispname)).encode('utf-8')))
f.write(compressor.flush()) f.write(compressor.flush())
self.info('done') logger.info('done')
def dump_search_index(self): def dump_search_index(self):
# type: () -> None # type: () -> None
self.info( logger.info(
bold('dumping search index in %s ... ' % self.indexer.label()), bold('dumping search index in %s ... ' % self.indexer.label()),
nonl=True) nonl=True)
self.indexer.prune(self.env.all_docs) self.indexer.prune(self.env.all_docs)
@ -931,7 +933,7 @@ class StandaloneHTMLBuilder(Builder):
with f: with f:
self.indexer.dump(f, self.indexer_format) # type: ignore self.indexer.dump(f, self.indexer_format) # type: ignore
movefile(searchindexfn + '.tmp', searchindexfn) movefile(searchindexfn + '.tmp', searchindexfn)
self.info('done') logger.info('done')
class DirectoryHTMLBuilder(StandaloneHTMLBuilder): class DirectoryHTMLBuilder(StandaloneHTMLBuilder):
@ -1097,36 +1099,36 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
# type: (Any) -> None # type: (Any) -> None
docnames = self.env.all_docs docnames = self.env.all_docs
self.info(bold('preparing documents... '), nonl=True) logger.info(bold('preparing documents... '), nonl=True)
self.prepare_writing(docnames) self.prepare_writing(docnames)
self.info('done') logger.info('done')
self.info(bold('assembling single document... '), nonl=True) logger.info(bold('assembling single document... '), nonl=True)
doctree = self.assemble_doctree() doctree = self.assemble_doctree()
self.env.toc_secnumbers = self.assemble_toc_secnumbers() self.env.toc_secnumbers = self.assemble_toc_secnumbers()
self.env.toc_fignumbers = self.assemble_toc_fignumbers() self.env.toc_fignumbers = self.assemble_toc_fignumbers()
self.info() logger.info('')
self.info(bold('writing... '), nonl=True) logger.info(bold('writing... '), nonl=True)
self.write_doc_serialized(self.config.master_doc, doctree) self.write_doc_serialized(self.config.master_doc, doctree)
self.write_doc(self.config.master_doc, doctree) self.write_doc(self.config.master_doc, doctree)
self.info('done') logger.info('done')
def finish(self): def finish(self):
# type: () -> None # type: () -> None
# no indices or search pages are supported # no indices or search pages are supported
self.info(bold('writing additional files...'), nonl=1) logger.info(bold('writing additional files...'), nonl=1)
# additional pages from conf.py # additional pages from conf.py
for pagename, template in self.config.html_additional_pages.items(): for pagename, template in self.config.html_additional_pages.items():
self.info(' '+pagename, nonl=1) logger.info(' '+pagename, nonl=1)
self.handle_page(pagename, {}, template) self.handle_page(pagename, {}, template)
if self.config.html_use_opensearch: if self.config.html_use_opensearch:
self.info(' opensearch', nonl=1) logger.info(' opensearch', nonl=1)
fn = path.join(self.outdir, '_static', 'opensearch.xml') fn = path.join(self.outdir, '_static', 'opensearch.xml')
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn) self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
self.info() logger.info('')
self.copy_image_files() self.copy_image_files()
self.copy_download_files() self.copy_download_files()

View File

@ -18,11 +18,15 @@ from os import path
from docutils import nodes from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.util.osutil import make_filename
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.util import logging
from sphinx.util.osutil import make_filename
from sphinx.util.pycompat import htmlescape from sphinx.util.pycompat import htmlescape
logger = logging.getLogger(__name__)
# Project file (*.hhp) template. 'outname' is the file basename (like # Project file (*.hhp) template. 'outname' is the file basename (like
# the pythlp in pythlp.hhp); 'version' is the doc version number (like # the pythlp in pythlp.hhp); 'version' is the doc version number (like
# the 2.2 in Python 2.2). # the 2.2 in Python 2.2).
@ -207,12 +211,12 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
StandaloneHTMLBuilder.write_doc(self, docname, doctree) StandaloneHTMLBuilder.write_doc(self, docname, doctree)
def build_hhx(self, outdir, outname): def build_hhx(self, outdir, outname):
self.info('dumping stopword list...') logger.info('dumping stopword list...')
with self.open_file(outdir, outname+'.stp') as f: with self.open_file(outdir, outname+'.stp') as f:
for word in sorted(stopwords): for word in sorted(stopwords):
print(word, file=f) print(word, file=f)
self.info('writing project file...') logger.info('writing project file...')
with self.open_file(outdir, outname+'.hhp') as f: with self.open_file(outdir, outname+'.hhp') as f:
f.write(project_template % { f.write(project_template % {
'outname': outname, 'outname': outname,
@ -233,7 +237,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
print(path.join(root, fn)[olen:].replace(os.sep, '\\'), print(path.join(root, fn)[olen:].replace(os.sep, '\\'),
file=f) file=f)
self.info('writing TOC file...') logger.info('writing TOC file...')
with self.open_file(outdir, outname+'.hhc') as f: with self.open_file(outdir, outname+'.hhc') as f:
f.write(contents_header) f.write(contents_header)
# special books # special books
@ -273,7 +277,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
write_toc(node) write_toc(node)
f.write(contents_footer) f.write(contents_footer)
self.info('writing index file...') logger.info('writing index file...')
index = self.env.create_index(self) index = self.env.create_index(self)
with self.open_file(outdir, outname+'.hhk') as f: with self.open_file(outdir, outname+'.hhk') as f:
f.write('<UL>\n') f.write('<UL>\n')

View File

@ -20,7 +20,7 @@ from docutils.utils import new_document
from docutils.frontend import OptionParser from docutils.frontend import OptionParser
from sphinx import package_dir, addnodes, highlighting from sphinx import package_dir, addnodes, highlighting
from sphinx.util import texescape from sphinx.util import texescape, logging
from sphinx.config import string_classes, ENUM from sphinx.config import string_classes, ENUM
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from sphinx.locale import _ from sphinx.locale import _
@ -38,6 +38,9 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
class LaTeXBuilder(Builder): class LaTeXBuilder(Builder):
""" """
Builds LaTeX output to create PDF. Builds LaTeX output to create PDF.
@ -119,7 +122,7 @@ class LaTeXBuilder(Builder):
destination = FileOutput( destination = FileOutput(
destination_path=path.join(self.outdir, targetname), destination_path=path.join(self.outdir, targetname),
encoding='utf-8') encoding='utf-8')
self.info("processing " + targetname + "... ", nonl=1) logger.info("processing " + targetname + "... ", nonl=1)
toctrees = self.env.get_doctree(docname).traverse(addnodes.toctree) toctrees = self.env.get_doctree(docname).traverse(addnodes.toctree)
if toctrees: if toctrees:
if toctrees[0].get('maxdepth') > 0: if toctrees[0].get('maxdepth') > 0:
@ -133,7 +136,7 @@ class LaTeXBuilder(Builder):
appendices=((docclass != 'howto') and self.config.latex_appendices or [])) appendices=((docclass != 'howto') and self.config.latex_appendices or []))
doctree['tocdepth'] = tocdepth doctree['tocdepth'] = tocdepth
self.post_process_images(doctree) self.post_process_images(doctree)
self.info("writing... ", nonl=1) logger.info("writing... ", nonl=1)
doctree.settings = docsettings doctree.settings = docsettings
doctree.settings.author = author doctree.settings.author = author
doctree.settings.title = title doctree.settings.title = title
@ -141,7 +144,7 @@ class LaTeXBuilder(Builder):
doctree.settings.docname = docname doctree.settings.docname = docname
doctree.settings.docclass = docclass doctree.settings.docclass = docclass
docwriter.write(doctree, destination) docwriter.write(doctree, destination)
self.info("done") logger.info("done")
def get_contentsname(self, indexfile): def get_contentsname(self, indexfile):
# type: (unicode) -> unicode # type: (unicode) -> unicode
@ -157,7 +160,7 @@ class LaTeXBuilder(Builder):
def assemble_doctree(self, indexfile, toctree_only, appendices): def assemble_doctree(self, indexfile, toctree_only, appendices):
# type: (unicode, bool, List[unicode]) -> nodes.Node # type: (unicode, bool, List[unicode]) -> nodes.Node
self.docnames = set([indexfile] + appendices) self.docnames = set([indexfile] + appendices)
self.info(darkgreen(indexfile) + " ", nonl=1) logger.info(darkgreen(indexfile) + " ", nonl=1)
tree = self.env.get_doctree(indexfile) tree = self.env.get_doctree(indexfile)
tree['docname'] = indexfile tree['docname'] = indexfile
if toctree_only: if toctree_only:
@ -178,8 +181,8 @@ class LaTeXBuilder(Builder):
appendix = self.env.get_doctree(docname) appendix = self.env.get_doctree(docname)
appendix['docname'] = docname appendix['docname'] = docname
largetree.append(appendix) largetree.append(appendix)
self.info() logger.info('')
self.info("resolving references...") logger.info("resolving references...")
self.env.resolve_references(largetree, indexfile, self) self.env.resolve_references(largetree, indexfile, self)
# resolve :ref:s to distant tex files -- we can't add a cross-reference, # resolve :ref:s to distant tex files -- we can't add a cross-reference,
# but append the document name # but append the document name
@ -202,16 +205,16 @@ class LaTeXBuilder(Builder):
# type: () -> None # type: () -> None
# copy image files # copy image files
if self.images: if self.images:
self.info(bold('copying images...'), nonl=1) logger.info(bold('copying images...'), nonl=1)
for src, dest in iteritems(self.images): for src, dest in iteritems(self.images):
self.info(' '+src, nonl=1) logger.info(' '+src, nonl=1)
copy_asset_file(path.join(self.srcdir, src), copy_asset_file(path.join(self.srcdir, src),
path.join(self.outdir, dest)) path.join(self.outdir, dest))
self.info() logger.info('')
# copy TeX support files from texinputs # copy TeX support files from texinputs
context = {'latex_engine': self.config.latex_engine} context = {'latex_engine': self.config.latex_engine}
self.info(bold('copying TeX support files...')) logger.info(bold('copying TeX support files...'))
staticdirname = path.join(package_dir, 'texinputs') staticdirname = path.join(package_dir, 'texinputs')
for filename in os.listdir(staticdirname): for filename in os.listdir(staticdirname):
if not filename.startswith('.'): if not filename.startswith('.'):
@ -220,11 +223,11 @@ class LaTeXBuilder(Builder):
# copy additional files # copy additional files
if self.config.latex_additional_files: if self.config.latex_additional_files:
self.info(bold('copying additional files...'), nonl=1) logger.info(bold('copying additional files...'), nonl=1)
for filename in self.config.latex_additional_files: for filename in self.config.latex_additional_files:
self.info(' '+filename, nonl=1) logger.info(' '+filename, nonl=1)
copy_asset_file(path.join(self.confdir, filename), self.outdir) copy_asset_file(path.join(self.confdir, filename), self.outdir)
self.info() logger.info('')
# the logo is handled differently # the logo is handled differently
if self.config.latex_logo: if self.config.latex_logo:
@ -232,7 +235,7 @@ class LaTeXBuilder(Builder):
raise SphinxError('logo file %r does not exist' % self.config.latex_logo) raise SphinxError('logo file %r does not exist' % self.config.latex_logo)
else: else:
copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir) copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir)
self.info('done') logger.info('done')
def validate_config_values(app): def validate_config_values(app):

View File

@ -19,7 +19,6 @@ from requests.exceptions import HTTPError
from six.moves import queue # type: ignore from six.moves import queue # type: ignore
from six.moves.urllib.parse import unquote from six.moves.urllib.parse import unquote
from six.moves.html_parser import HTMLParser from six.moves.html_parser import HTMLParser
from docutils import nodes from docutils import nodes
# 2015-06-25 barry@python.org. This exception was deprecated in Python 3.3 and # 2015-06-25 barry@python.org. This exception was deprecated in Python 3.3 and
@ -33,7 +32,7 @@ except ImportError:
pass pass
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.util import encode_uri, requests from sphinx.util import encode_uri, requests, logging
from sphinx.util.console import ( # type: ignore from sphinx.util.console import ( # type: ignore
purple, red, darkgreen, darkgray, darkred, turquoise purple, red, darkgreen, darkgray, darkred, turquoise
) )
@ -46,6 +45,9 @@ if False:
from sphinx.util.requests.requests import Response # NOQA from sphinx.util.requests.requests import Response # NOQA
logger = logging.getLogger(__name__)
class AnchorCheckParser(HTMLParser): class AnchorCheckParser(HTMLParser):
"""Specialized HTML parser that looks for a specific anchor.""" """Specialized HTML parser that looks for a specific anchor."""
@ -231,24 +233,24 @@ class CheckExternalLinksBuilder(Builder):
if status == 'working' and info == 'old': if status == 'working' and info == 'old':
return return
if lineno: if lineno:
self.info('(line %4d) ' % lineno, nonl=1) logger.info('(line %4d) ' % lineno, nonl=1)
if status == 'ignored': if status == 'ignored':
if info: if info:
self.info(darkgray('-ignored- ') + uri + ': ' + info) logger.info(darkgray('-ignored- ') + uri + ': ' + info)
else: else:
self.info(darkgray('-ignored- ') + uri) logger.info(darkgray('-ignored- ') + uri)
elif status == 'local': elif status == 'local':
self.info(darkgray('-local- ') + uri) logger.info(darkgray('-local- ') + uri)
self.write_entry('local', docname, lineno, uri) self.write_entry('local', docname, lineno, uri)
elif status == 'working': elif status == 'working':
self.info(darkgreen('ok ') + uri + info) logger.info(darkgreen('ok ') + uri + info)
elif status == 'broken': elif status == 'broken':
self.write_entry('broken', docname, lineno, uri + ': ' + info) self.write_entry('broken', docname, lineno, uri + ': ' + info)
if self.app.quiet or self.app.warningiserror: if self.app.quiet or self.app.warningiserror:
self.warn('broken link: %s (%s)' % (uri, info), self.warn('broken link: %s (%s)' % (uri, info),
'%s:%s' % (self.env.doc2path(docname), lineno)) '%s:%s' % (self.env.doc2path(docname), lineno))
else: else:
self.info(red('broken ') + uri + red(' - ' + info)) logger.info(red('broken ') + uri + red(' - ' + info))
elif status == 'redirected': elif status == 'redirected':
text, color = { text, color = {
301: ('permanently', darkred), 301: ('permanently', darkred),
@ -259,7 +261,7 @@ class CheckExternalLinksBuilder(Builder):
}[code] }[code]
self.write_entry('redirected ' + text, docname, lineno, self.write_entry('redirected ' + text, docname, lineno,
uri + ' to ' + info) uri + ' to ' + info)
self.info(color('redirect ') + uri + color(' - ' + text + ' to ' + info)) logger.info(color('redirect ') + uri + color(' - ' + text + ' to ' + info))
def get_target_uri(self, docname, typ=None): def get_target_uri(self, docname, typ=None):
# type: (unicode, unicode) -> unicode # type: (unicode, unicode) -> unicode
@ -275,7 +277,7 @@ class CheckExternalLinksBuilder(Builder):
def write_doc(self, docname, doctree): def write_doc(self, docname, doctree):
# type: (unicode, nodes.Node) -> None # type: (unicode, nodes.Node) -> None
self.info() logger.info('')
n = 0 n = 0
for node in doctree.traverse(nodes.reference): for node in doctree.traverse(nodes.reference):
if 'refuri' not in node: if 'refuri' not in node:

View File

@ -19,6 +19,7 @@ from docutils.frontend import OptionParser
from sphinx import addnodes from sphinx import addnodes
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.environment import NoUri from sphinx.environment import NoUri
from sphinx.util import logging
from sphinx.util.nodes import inline_all_toctrees from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import make_filename from sphinx.util.osutil import make_filename
from sphinx.util.console import bold, darkgreen # type: ignore from sphinx.util.console import bold, darkgreen # type: ignore
@ -30,6 +31,9 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
class ManualPageBuilder(Builder): class ManualPageBuilder(Builder):
""" """
Builds groff output in manual page format. Builds groff output in manual page format.
@ -62,7 +66,7 @@ class ManualPageBuilder(Builder):
components=(docwriter,), components=(docwriter,),
read_config_files=True).get_default_values() read_config_files=True).get_default_values()
self.info(bold('writing... '), nonl=True) logger.info(bold('writing... '), nonl=True)
for info in self.config.man_pages: for info in self.config.man_pages:
docname, name, description, authors, section = info docname, name, description, authors, section = info
@ -73,7 +77,7 @@ class ManualPageBuilder(Builder):
authors = [] authors = []
targetname = '%s.%s' % (name, section) targetname = '%s.%s' % (name, section)
self.info(darkgreen(targetname) + ' { ', nonl=True) logger.info(darkgreen(targetname) + ' { ', nonl=True)
destination = FileOutput( destination = FileOutput(
destination_path=path.join(self.outdir, targetname), destination_path=path.join(self.outdir, targetname),
encoding='utf-8') encoding='utf-8')
@ -82,7 +86,7 @@ class ManualPageBuilder(Builder):
docnames = set() # type: Set[unicode] docnames = set() # type: Set[unicode]
largetree = inline_all_toctrees(self, docnames, docname, tree, largetree = inline_all_toctrees(self, docnames, docname, tree,
darkgreen, [docname]) darkgreen, [docname])
self.info('} ', nonl=True) logger.info('} ', nonl=True)
self.env.resolve_references(largetree, docname, self) self.env.resolve_references(largetree, docname, self)
# remove pending_xref nodes # remove pending_xref nodes
for pendingnode in largetree.traverse(addnodes.pending_xref): for pendingnode in largetree.traverse(addnodes.pending_xref):
@ -95,7 +99,7 @@ class ManualPageBuilder(Builder):
largetree.settings.section = section largetree.settings.section = section
docwriter.write(largetree, destination) docwriter.write(largetree, destination)
self.info() logger.info('')
def finish(self): def finish(self):
# type: () -> None # type: () -> None

View File

@ -21,7 +21,7 @@ from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.util import force_decode from sphinx.util import force_decode, logging
from sphinx.util.osutil import make_filename from sphinx.util.osutil import make_filename
from sphinx.util.pycompat import htmlescape from sphinx.util.pycompat import htmlescape
@ -31,6 +31,9 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
_idpattern = re.compile( _idpattern = re.compile(
r'(?P<title>.+) (\((class in )?(?P<id>[\w\.]+)( (?P<descr>\w+))?\))$') r'(?P<title>.+) (\((class in )?(?P<id>[\w\.]+)( (?P<descr>\w+))?\))$')
@ -138,7 +141,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
def build_qhp(self, outdir, outname): def build_qhp(self, outdir, outname):
# type: (unicode, unicode) -> None # type: (unicode, unicode) -> None
self.info('writing project file...') logger.info('writing project file...')
# sections # sections
tocdoc = self.env.get_and_resolve_doctree(self.config.master_doc, self, tocdoc = self.env.get_and_resolve_doctree(self.config.master_doc, self,
@ -216,7 +219,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
nspace, 'doc', self.get_target_uri(self.config.master_doc)) nspace, 'doc', self.get_target_uri(self.config.master_doc))
startpage = 'qthelp://' + posixpath.join(nspace, 'doc', 'index.html') startpage = 'qthelp://' + posixpath.join(nspace, 'doc', 'index.html')
self.info('writing collection project file...') logger.info('writing collection project file...')
with codecs.open(path.join(outdir, outname+'.qhcp'), 'w', 'utf-8') as f: # type: ignore # NOQA with codecs.open(path.join(outdir, outname+'.qhcp'), 'w', 'utf-8') as f: # type: ignore # NOQA
f.write(collection_template % { # type: ignore f.write(collection_template % { # type: ignore
'outname': htmlescape(outname), 'outname': htmlescape(outname),

View File

@ -22,6 +22,7 @@ from sphinx import addnodes
from sphinx.locale import _ from sphinx.locale import _
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.environment import NoUri from sphinx.environment import NoUri
from sphinx.util import logging
from sphinx.util.nodes import inline_all_toctrees from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, copyfile, make_filename from sphinx.util.osutil import SEP, copyfile, make_filename
from sphinx.util.console import bold, darkgreen # type: ignore from sphinx.util.console import bold, darkgreen # type: ignore
@ -33,6 +34,8 @@ if False:
from typing import Any, Iterable, Tuple, Union # NOQA from typing import Any, Iterable, Tuple, Union # NOQA
logger = logging.getLogger(__name__)
TEXINFO_MAKEFILE = '''\ TEXINFO_MAKEFILE = '''\
# Makefile for Sphinx Texinfo output # Makefile for Sphinx Texinfo output
@ -152,11 +155,11 @@ class TexinfoBuilder(Builder):
destination = FileOutput( destination = FileOutput(
destination_path=path.join(self.outdir, targetname), destination_path=path.join(self.outdir, targetname),
encoding='utf-8') encoding='utf-8')
self.info("processing " + targetname + "... ", nonl=1) logger.info("processing " + targetname + "... ", nonl=1)
doctree = self.assemble_doctree( doctree = self.assemble_doctree(
docname, toctree_only, docname, toctree_only,
appendices=(self.config.texinfo_appendices or [])) appendices=(self.config.texinfo_appendices or []))
self.info("writing... ", nonl=1) logger.info("writing... ", nonl=1)
self.post_process_images(doctree) self.post_process_images(doctree)
docwriter = TexinfoWriter(self) docwriter = TexinfoWriter(self)
settings = OptionParser( settings = OptionParser(
@ -173,12 +176,12 @@ class TexinfoBuilder(Builder):
settings.docname = docname settings.docname = docname
doctree.settings = settings doctree.settings = settings
docwriter.write(doctree, destination) docwriter.write(doctree, destination)
self.info("done") logger.info("done")
def assemble_doctree(self, indexfile, toctree_only, appendices): def assemble_doctree(self, indexfile, toctree_only, appendices):
# type: (unicode, bool, List[unicode]) -> nodes.Node # type: (unicode, bool, List[unicode]) -> nodes.Node
self.docnames = set([indexfile] + appendices) self.docnames = set([indexfile] + appendices)
self.info(darkgreen(indexfile) + " ", nonl=1) logger.info(darkgreen(indexfile) + " ", nonl=1)
tree = self.env.get_doctree(indexfile) tree = self.env.get_doctree(indexfile)
tree['docname'] = indexfile tree['docname'] = indexfile
if toctree_only: if toctree_only:
@ -199,8 +202,8 @@ class TexinfoBuilder(Builder):
appendix = self.env.get_doctree(docname) appendix = self.env.get_doctree(docname)
appendix['docname'] = docname appendix['docname'] = docname
largetree.append(appendix) largetree.append(appendix)
self.info() logger.info('')
self.info("resolving references...") logger.info("resolving references...")
self.env.resolve_references(largetree, indexfile, self) self.env.resolve_references(largetree, indexfile, self)
# TODO: add support for external :ref:s # TODO: add support for external :ref:s
for pendingnode in largetree.traverse(addnodes.pending_xref): for pendingnode in largetree.traverse(addnodes.pending_xref):
@ -222,23 +225,23 @@ class TexinfoBuilder(Builder):
# type: () -> None # type: () -> None
# copy image files # copy image files
if self.images: if self.images:
self.info(bold('copying images...'), nonl=1) logger.info(bold('copying images...'), nonl=1)
for src, dest in iteritems(self.images): for src, dest in iteritems(self.images):
self.info(' '+src, nonl=1) logger.info(' '+src, nonl=1)
copyfile(path.join(self.srcdir, src), copyfile(path.join(self.srcdir, src),
path.join(self.outdir, dest)) path.join(self.outdir, dest))
self.info() logger.info('')
self.info(bold('copying Texinfo support files... '), nonl=True) logger.info(bold('copying Texinfo support files... '), nonl=True)
# copy Makefile # copy Makefile
fn = path.join(self.outdir, 'Makefile') fn = path.join(self.outdir, 'Makefile')
self.info(fn, nonl=1) logger.info(fn, nonl=1)
try: try:
with open(fn, 'w') as mkfile: with open(fn, 'w') as mkfile:
mkfile.write(TEXINFO_MAKEFILE) mkfile.write(TEXINFO_MAKEFILE)
except (IOError, OSError) as err: except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (fn, err)) self.warn("error writing file %s: %s" % (fn, err))
self.info(' done') logger.info(' done')
def setup(app): def setup(app):

View File

@ -33,7 +33,7 @@ from docutils.frontend import OptionParser
from sphinx import addnodes from sphinx import addnodes
from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput
from sphinx.util import get_matching_docs, docname_join, FilenameUniqDict from sphinx.util import get_matching_docs, docname_join, FilenameUniqDict, logging
from sphinx.util.nodes import clean_astext, WarningStream, is_translatable, \ from sphinx.util.nodes import clean_astext, WarningStream, is_translatable, \
process_only_nodes process_only_nodes
from sphinx.util.osutil import SEP, getcwd, fs_encoding, ensuredir from sphinx.util.osutil import SEP, getcwd, fs_encoding, ensuredir
@ -60,6 +60,8 @@ if False:
from sphinx.domains import Domain # NOQA from sphinx.domains import Domain # NOQA
from sphinx.environment.managers import EnvironmentManager # NOQA from sphinx.environment.managers import EnvironmentManager # NOQA
logger = logging.getLogger(__name__)
default_settings = { default_settings = {
'embed_stylesheet': False, 'embed_stylesheet': False,
'cloak_email_addresses': True, 'cloak_email_addresses': True,
@ -553,7 +555,7 @@ class BuildEnvironment(object):
# this cache also needs to be updated every time # this cache also needs to be updated every time
self._nitpick_ignore = set(self.config.nitpick_ignore) self._nitpick_ignore = set(self.config.nitpick_ignore)
app.info(bold('updating environment: '), nonl=True) logger.info(bold('updating environment: '), nonl=True)
added, changed, removed = self.get_outdated_files(config_changed) added, changed, removed = self.get_outdated_files(config_changed)
@ -569,7 +571,7 @@ class BuildEnvironment(object):
msg += '%s added, %s changed, %s removed' % (len(added), len(changed), msg += '%s added, %s changed, %s removed' % (len(added), len(changed),
len(removed)) len(removed))
app.info(msg) logger.info(msg)
self.app = app self.app = app
@ -664,7 +666,7 @@ class BuildEnvironment(object):
tasks.add_task(read_process, chunk, merge) tasks.add_task(read_process, chunk, merge)
# make sure all threads have finished # make sure all threads have finished
app.info(bold('waiting for workers...')) logger.info(bold('waiting for workers...'))
tasks.join() tasks.join()
for warning, kwargs in warnings: for warning, kwargs in warnings:

View File

@ -31,6 +31,7 @@ from sphinx.util import rpartition, force_decode
from sphinx.locale import _ from sphinx.locale import _
from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.application import ExtensionError from sphinx.application import ExtensionError
from sphinx.util import logging
from sphinx.util.nodes import nested_parse_with_titles from sphinx.util.nodes import nested_parse_with_titles
from sphinx.util.inspect import getargspec, isdescriptor, safe_getmembers, \ from sphinx.util.inspect import getargspec, isdescriptor, safe_getmembers, \
safe_getattr, object_description, is_builtin_class_method, \ safe_getattr, object_description, is_builtin_class_method, \
@ -52,6 +53,8 @@ try:
except ImportError: except ImportError:
typing = None typing = None
logger = logging.getLogger(__name__)
# This type isn't exposed directly in any modules, but can be found # This type isn't exposed directly in any modules, but can be found
# here in most Python versions # here in most Python versions
MethodDescriptorType = type(type.__subclasses__) MethodDescriptorType = type(type.__subclasses__)
@ -581,26 +584,25 @@ class Documenter(object):
Returns True if successful, False if an error occurred. Returns True if successful, False if an error occurred.
""" """
dbg = self.env.app.debug
if self.objpath: if self.objpath:
dbg('[autodoc] from %s import %s', logger.debug('[autodoc] from %s import %s',
self.modname, '.'.join(self.objpath)) self.modname, '.'.join(self.objpath))
try: try:
dbg('[autodoc] import %s', self.modname) logger.debug('[autodoc] import %s', self.modname)
for modname in self.env.config.autodoc_mock_imports: for modname in self.env.config.autodoc_mock_imports:
dbg('[autodoc] adding a mock module %s!', modname) logger.debug('[autodoc] adding a mock module %s!', modname)
mock_import(modname) mock_import(modname)
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=ImportWarning) warnings.filterwarnings("ignore", category=ImportWarning)
__import__(self.modname) __import__(self.modname)
parent = None parent = None
obj = self.module = sys.modules[self.modname] obj = self.module = sys.modules[self.modname]
dbg('[autodoc] => %r', obj) logger.debug('[autodoc] => %r', obj)
for part in self.objpath: for part in self.objpath:
parent = obj parent = obj
dbg('[autodoc] getattr(_, %r)', part) logger.debug('[autodoc] getattr(_, %r)', part)
obj = self.get_attr(obj, part) obj = self.get_attr(obj, part)
dbg('[autodoc] => %r', obj) logger.debug('[autodoc] => %r', obj)
self.object_name = part self.object_name = part
self.parent = parent self.parent = parent
self.object = obj self.object = obj
@ -622,7 +624,7 @@ class Documenter(object):
traceback.format_exc() traceback.format_exc()
if PY2: if PY2:
errmsg = errmsg.decode('utf-8') # type: ignore errmsg = errmsg.decode('utf-8') # type: ignore
dbg(errmsg) logger.debug(errmsg)
self.directive.warn(errmsg) self.directive.warn(errmsg)
self.env.note_reread() self.env.note_reread()
return False return False
@ -1024,7 +1026,7 @@ class Documenter(object):
# be cached anyway) # be cached anyway)
self.analyzer.find_attr_docs() self.analyzer.find_attr_docs()
except PycodeError as err: except PycodeError as err:
self.env.app.debug('[autodoc] module analyzer failed: %s', err) logger.debug('[autodoc] module analyzer failed: %s', err)
# no source file -- e.g. for builtin and C modules # no source file -- e.g. for builtin and C modules
self.analyzer = None self.analyzer = None
# at least add the module.__file__ as a dependency # at least add the module.__file__ as a dependency
@ -1730,7 +1732,7 @@ class AutoDirective(Directive):
source, lineno = self.reporter.get_source_and_line(self.lineno) source, lineno = self.reporter.get_source_and_line(self.lineno)
except AttributeError: except AttributeError:
source = lineno = None source = lineno = None
self.env.app.debug('[autodoc] %s:%s: input:\n%s', logger.debug('[autodoc] %s:%s: input:\n%s',
source, lineno, self.block_text) source, lineno, self.block_text)
# find out what documenter to call # find out what documenter to call
@ -1760,7 +1762,7 @@ class AutoDirective(Directive):
if not self.result: if not self.result:
return self.warnings return self.warnings
self.env.app.debug2('[autodoc] output:\n%s', '\n'.join(self.result)) logger.debug2('[autodoc] output:\n%s', '\n'.join(self.result))
# record all filenames as dependencies -- this will at least # record all filenames as dependencies -- this will at least
# partially make automatic invalidation possible # partially make automatic invalidation possible

View File

@ -69,7 +69,7 @@ from docutils import nodes
import sphinx import sphinx
from sphinx import addnodes from sphinx import addnodes
from sphinx.util import import_object, rst from sphinx.util import import_object, rst, logging
from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.ext.autodoc import Options from sphinx.ext.autodoc import Options
@ -81,6 +81,8 @@ if False:
from sphinx.environment import BuildEnvironment # NOQA from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc import Documenter # NOQA from sphinx.ext.autodoc import Documenter # NOQA
logger = logging.getLogger(__name__)
# -- autosummary_toc node ------------------------------------------------------ # -- autosummary_toc node ------------------------------------------------------
@ -305,8 +307,7 @@ class Autosummary(Directive):
# be cached anyway) # be cached anyway)
documenter.analyzer.find_attr_docs() documenter.analyzer.find_attr_docs()
except PycodeError as err: except PycodeError as err:
documenter.env.app.debug( logger.debug('[autodoc] module analyzer failed: %s', err)
'[autodoc] module analyzer failed: %s', err)
# no source file -- e.g. for builtin and C modules # no source file -- e.g. for builtin and C modules
documenter.analyzer = None documenter.analyzer = None

View File

@ -25,7 +25,7 @@ from docutils.parsers.rst import Directive, directives
import sphinx import sphinx
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.util import force_decode from sphinx.util import force_decode, logging
from sphinx.util.nodes import set_source_info from sphinx.util.nodes import set_source_info
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
from sphinx.util.osutil import fs_encoding from sphinx.util.osutil import fs_encoding
@ -35,6 +35,8 @@ if False:
from typing import Any, Callable, IO, Iterable, Sequence, Tuple # NOQA from typing import Any, Callable, IO, Iterable, Sequence, Tuple # NOQA
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE) blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE) doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE)
@ -262,7 +264,7 @@ Results of doctest builder run on %s
def _out(self, text): def _out(self, text):
# type: (unicode) -> None # type: (unicode) -> None
self.info(text, nonl=True) logger.info(text, nonl=True)
self.outfile.write(text) self.outfile.write(text)
def _warn_out(self, text): def _warn_out(self, text):
@ -270,7 +272,7 @@ Results of doctest builder run on %s
if self.app.quiet or self.app.warningiserror: if self.app.quiet or self.app.warningiserror:
self.warn(text) self.warn(text)
else: else:
self.info(text, nonl=True) logger.info(text, nonl=True)
if isinstance(text, binary_type): if isinstance(text, binary_type):
text = force_decode(text, None) text = force_decode(text, None)
self.outfile.write(text) self.outfile.write(text)
@ -311,7 +313,7 @@ Doctest summary
if build_docnames is None: if build_docnames is None:
build_docnames = sorted(self.env.all_docs) build_docnames = sorted(self.env.all_docs)
self.info(bold('running tests...')) logger.info(bold('running tests...'))
for docname in build_docnames: for docname in build_docnames:
# no need to resolve the doctree # no need to resolve the doctree
doctree = self.env.get_doctree(docname) doctree = self.env.get_doctree(docname)

View File

@ -42,7 +42,7 @@ from docutils.utils import relative_path
import sphinx import sphinx
from sphinx.locale import _ from sphinx.locale import _
from sphinx.builders.html import INVENTORY_FILENAME from sphinx.builders.html import INVENTORY_FILENAME
from sphinx.util import requests from sphinx.util import requests, logging
if False: if False:
# For type annotation # For type annotation
@ -56,6 +56,7 @@ if False:
Inventory = Dict[unicode, Dict[unicode, Tuple[unicode, unicode, unicode, unicode]]] Inventory = Dict[unicode, Dict[unicode, Tuple[unicode, unicode, unicode, unicode]]]
logger = logging.getLogger(__name__)
UTF8StreamReader = codecs.lookup('utf-8')[2] UTF8StreamReader = codecs.lookup('utf-8')[2]
@ -235,7 +236,7 @@ def fetch_inventory(app, uri, inv):
if hasattr(f, 'url'): if hasattr(f, 'url'):
newinv = f.url # type: ignore newinv = f.url # type: ignore
if inv != newinv: if inv != newinv:
app.info('intersphinx inventory has moved: %s -> %s' % (inv, newinv)) logger.info('intersphinx inventory has moved: %s -> %s' % (inv, newinv))
if uri in (inv, path.dirname(inv), path.dirname(inv) + '/'): if uri in (inv, path.dirname(inv), path.dirname(inv) + '/'):
uri = path.dirname(newinv) uri = path.dirname(newinv)
@ -294,7 +295,7 @@ def load_mappings(app):
if '://' not in inv or uri not in cache \ if '://' not in inv or uri not in cache \
or cache[uri][1] < cache_time: or cache[uri][1] < cache_time:
safe_inv_url = _get_safe_url(inv) # type: ignore safe_inv_url = _get_safe_url(inv) # type: ignore
app.info( logger.info(
'loading intersphinx inventory from %s...' % safe_inv_url) 'loading intersphinx inventory from %s...' % safe_inv_url)
invdata = fetch_inventory(app, uri, inv) invdata = fetch_inventory(app, uri, inv)
if invdata: if invdata:

View File

@ -19,7 +19,7 @@ import sphinx
from sphinx import addnodes from sphinx import addnodes
from sphinx.locale import _ from sphinx.locale import _
from sphinx.pycode import ModuleAnalyzer from sphinx.pycode import ModuleAnalyzer
from sphinx.util import get_full_modname from sphinx.util import get_full_modname, logging
from sphinx.util.nodes import make_refnode from sphinx.util.nodes import make_refnode
from sphinx.util.console import blue # type: ignore from sphinx.util.console import blue # type: ignore
@ -29,6 +29,8 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
from sphinx.environment import BuildEnvironment # NOQA from sphinx.environment import BuildEnvironment # NOQA
logger = logging.getLogger(__name__)
def _get_full_modname(app, modname, attribute): def _get_full_modname(app, modname, attribute):
# type: (Sphinx, str, unicode) -> unicode # type: (Sphinx, str, unicode) -> unicode
@ -37,15 +39,15 @@ def _get_full_modname(app, modname, attribute):
except AttributeError: except AttributeError:
# sphinx.ext.viewcode can't follow class instance attribute # sphinx.ext.viewcode can't follow class instance attribute
# then AttributeError logging output only verbose mode. # then AttributeError logging output only verbose mode.
app.verbose('Didn\'t find %s in %s' % (attribute, modname)) logger.verbose('Didn\'t find %s in %s' % (attribute, modname))
return None return None
except Exception as e: except Exception as e:
# sphinx.ext.viewcode follow python domain directives. # sphinx.ext.viewcode follow python domain directives.
# because of that, if there are no real modules exists that specified # because of that, if there are no real modules exists that specified
# by py:function or other directives, viewcode emits a lot of warnings. # by py:function or other directives, viewcode emits a lot of warnings.
# It should be displayed only verbose mode. # It should be displayed only verbose mode.
app.verbose(traceback.format_exc().rstrip()) logger.verbose(traceback.format_exc().rstrip())
app.verbose('viewcode can\'t import %s, failed with error "%s"' % logger.verbose('viewcode can\'t import %s, failed with error "%s"' %
(modname, e)) (modname, e))
return None return None

View File

@ -15,9 +15,13 @@ from docutils.transforms.parts import ContentsFilter
from sphinx import addnodes from sphinx import addnodes
from sphinx.locale import _ from sphinx.locale import _
from sphinx.util import logging
from sphinx.util.i18n import format_date from sphinx.util.i18n import format_date
from sphinx.util.nodes import apply_source_workaround from sphinx.util.nodes import apply_source_workaround
logger = logging.getLogger(__name__)
default_substitutions = set([ default_substitutions = set([
'version', 'version',
'release', 'release',
@ -215,7 +219,7 @@ class FilterSystemMessages(Transform):
filterlevel = env.config.keep_warnings and 2 or 5 filterlevel = env.config.keep_warnings and 2 or 5
for node in self.document.traverse(nodes.system_message): for node in self.document.traverse(nodes.system_message):
if node['level'] < filterlevel: if node['level'] < filterlevel:
env.app.debug('%s [filtered system message]', node.astext()) logger.debug('%s [filtered system message]', node.astext())
node.parent.remove(node) node.parent.remove(node)

View File

@ -28,6 +28,7 @@ from six.moves.urllib.parse import urlsplit, urlunsplit, quote_plus, parse_qsl,
from docutils.utils import relative_path from docutils.utils import relative_path
from sphinx.errors import PycodeError, SphinxParallelError, ExtensionError from sphinx.errors import PycodeError, SphinxParallelError, ExtensionError
from sphinx.util import logging
from sphinx.util.console import strip_colors from sphinx.util.console import strip_colors
from sphinx.util.fileutil import copy_asset_file from sphinx.util.fileutil import copy_asset_file
from sphinx.util.osutil import fs_encoding from sphinx.util.osutil import fs_encoding
@ -46,6 +47,9 @@ if False:
# For type annotation # For type annotation
from typing import Any, Callable, Iterable, Pattern, Sequence, Tuple # NOQA from typing import Any, Callable, Iterable, Pattern, Sequence, Tuple # NOQA
logger = logging.getLogger(__name__)
# Generally useful regular expressions. # Generally useful regular expressions.
ws_re = re.compile(r'\s+') # type: Pattern ws_re = re.compile(r'\s+') # type: Pattern
url_re = re.compile(r'(?P<schema>.+)://.*') # type: Pattern url_re = re.compile(r'(?P<schema>.+)://.*') # type: Pattern
@ -532,3 +536,12 @@ def split_docinfo(text):
return '', result[0] return '', result[0]
else: else:
return result[1:] return result[1:]
def display_chunk(chunk):
# type: (Union[List, Tuple, unicode]) -> unicode
if isinstance(chunk, (list, tuple)):
if len(chunk) == 1:
return text_type(chunk[0])
return '%s .. %s' % (chunk[0], chunk[-1])
return text_type(chunk)