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.osutil import ENOENT
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
@ -164,13 +164,13 @@ class Sphinx(object):
self.messagelog = deque(maxlen=10) # type: deque
# 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
self.statuscode = 0
if not path.isdir(outdir):
self.info('making output directory...')
logger.info('making output directory...')
os.makedirs(outdir)
# read config
@ -267,8 +267,8 @@ class Sphinx(object):
the configuration.
"""
if self.config.language is not None:
self.info(bold('loading translations [%s]... ' %
self.config.language), nonl=True)
logger.info(bold('loading translations [%s]... ' % self.config.language),
nonl=True)
user_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
@ -283,9 +283,9 @@ class Sphinx(object):
if self.config.language is not None:
if has_translation or self.config.language == 'en':
# "en" never needs to be translated
self.info('done')
logger.info('done')
else:
self.info('not available for built-in messages')
logger.info('not available for built-in messages')
def _init_source_parsers(self):
# type: () -> None
@ -305,7 +305,7 @@ class Sphinx(object):
self.env.domains[domain] = self.domains[domain](self.env)
else:
try:
self.info(bold('loading pickled environment... '), nonl=True)
logger.info(bold('loading pickled environment... '), nonl=True)
self.env = BuildEnvironment.frompickle(
self.srcdir, self.config, path.join(self.doctreedir, ENV_PICKLE_FILENAME))
self.env.set_warnfunc(self.warn)
@ -314,12 +314,12 @@ class Sphinx(object):
for domain in self.domains.keys():
# this can raise if the data version doesn't fit
self.env.domains[domain] = self.domains[domain](self.env)
self.info('done')
logger.info('done')
except Exception as err:
if isinstance(err, IOError) and err.errno == ENOENT:
self.info('not yet created')
logger.info('not yet created')
else:
self.info('failed: %s' % err)
logger.info('failed: %s' % err)
self._init_env(freshenv=True)
def _init_builder(self, buildername):
@ -357,11 +357,11 @@ class Sphinx(object):
status = (self.statuscode == 0 and
'succeeded' or 'finished with problems')
if self._warncount:
self.info(bold('build %s, %s warning%s.' %
(status, self._warncount,
self._warncount != 1 and 's' or '')))
logger.info(bold('build %s, %s warning%s.' %
(status, self._warncount,
self._warncount != 1 and 's' or '')))
else:
self.info(bold('build %s.' % status))
logger.info(bold('build %s.' % status))
except Exception as err:
# delete the saved env to force a fresh build next time
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
@ -374,22 +374,6 @@ class Sphinx(object):
self.builder.cleanup()
# ---- 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,
type=None, subtype=None, colorfunc=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
more info output will follow soon.)
"""
self._log(message, self._status, nonl)
logger.info(message, nonl=nonl)
def verbose(self, message, *args, **kwargs):
# type: (unicode, Any, Any) -> None
"""Emit a verbose informational message.
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)
"""Emit a verbose informational message."""
logger.verbose(message, *args, **kwargs)
def debug(self, message, *args, **kwargs):
# type: (unicode, Any, Any) -> None
"""Emit a debug-level informational message.
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)
"""Emit a debug-level informational message."""
logger.debug(message, *args, **kwargs)
def debug2(self, message, *args, **kwargs):
# type: (unicode, Any, Any) -> None
"""Emit a lowlevel debug-level informational message.
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)
"""Emit a lowlevel debug-level informational message."""
logger.debug2(message, *args, **kwargs)
def _display_chunk(chunk):
# type: (Any) -> unicode
# type: (Union[List, Tuple, unicode]) -> unicode
if isinstance(chunk, (list, tuple)):
if len(chunk) == 1:
return text_type(chunk[0])
@ -484,21 +435,21 @@ class Sphinx(object):
def old_status_iterator(self, iterable, summary, colorfunc=darkgreen,
stringify_func=_display_chunk):
# type: (Iterable, unicode, Callable, Callable) -> Iterator
# type: (Iterable, unicode, Callable, Callable[[Any], unicode]) -> Iterator
l = 0
for item in iterable:
if l == 0:
self.info(bold(summary), nonl=True)
logger.info(bold(summary), nonl=True)
l = 1
self.info(colorfunc(stringify_func(item)) + ' ', nonl=True)
logger.info(colorfunc(stringify_func(item)) + ' ', nonl=True)
yield item
if l == 1:
self.info()
logger.info('')
# new version with progress info
def status_iterator(self, iterable, summary, colorfunc=darkgreen, length=0,
stringify_func=_display_chunk):
# type: (Iterable, unicode, Callable, int, Callable) -> Iterable
# type: (Iterable, unicode, Callable, int, Callable[[Any], unicode]) -> Iterable
if length == 0:
for item in self.old_status_iterator(iterable, summary, colorfunc,
stringify_func):
@ -514,17 +465,17 @@ class Sphinx(object):
s += '\n'
else:
s = term_width_line(s)
self.info(s, nonl=True)
logger.info(s, nonl=True)
yield item
if l > 0:
self.info()
logger.info('')
# ---- general extensibility interface -------------------------------------
def setup_extension(self, extension):
# type: (unicode) -> None
"""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:
return
if extension in EXTENSION_BLACKLIST:
@ -536,7 +487,7 @@ class Sphinx(object):
try:
mod = __import__(extension, None, None, ['setup'])
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,
err)
if not hasattr(mod, 'setup'):
@ -596,20 +547,20 @@ class Sphinx(object):
else:
self._listeners[event][listener_id] = callback
self.next_listener_id += 1
self.debug('[app] connecting event %r: %r [id=%s]',
event, callback, listener_id)
logger.debug('[app] connecting event %r: %r [id=%s]',
event, callback, listener_id)
return listener_id
def disconnect(self, listener_id):
# 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):
event.pop(listener_id, None)
def emit(self, event, *args):
# type: (unicode, Any) -> List
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:
# not every object likes to be repr()'d (think
# random stuff coming via autodoc)
@ -631,7 +582,7 @@ class Sphinx(object):
def add_builder(self, builder):
# type: (Type[Builder]) -> None
self.debug('[app] adding builder: %r', builder)
logger.debug('[app] adding builder: %r', builder)
if not hasattr(builder, 'name'):
raise ExtensionError('Builder class %s has no "name" attribute'
% builder)
@ -643,8 +594,8 @@ class Sphinx(object):
def add_config_value(self, name, default, rebuild, types=()):
# type: (unicode, Any, Union[bool, unicode], Any) -> None
self.debug('[app] adding config value: %r',
(name, default, rebuild) + ((types,) if types else ())) # type: ignore
logger.debug('[app] adding config value: %r',
(name, default, rebuild) + ((types,) if types else ())) # type: ignore
if name in self.config.values:
raise ExtensionError('Config value %r already present' % name)
if rebuild in (False, True):
@ -653,19 +604,19 @@ class Sphinx(object):
def add_event(self, name):
# type: (unicode) -> None
self.debug('[app] adding event: %r', name)
logger.debug('[app] adding event: %r', name)
if name in self._events:
raise ExtensionError('Event %r already present' % name)
self._events[name] = ''
def set_translator(self, name, translator_class):
# 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
def add_node(self, node, **kwds):
# 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 \
hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__):
logger.warning('while setting up extension %s: node class %r is '
@ -719,8 +670,8 @@ class Sphinx(object):
def add_directive(self, name, obj, content=None, arguments=None, **options):
# type: (unicode, Any, unicode, Any, Any) -> None
self.debug('[app] adding directive: %r',
(name, obj, content, arguments, options))
logger.debug('[app] adding directive: %r',
(name, obj, content, arguments, options))
if name in directives._directives:
logger.warning('while setting up extension %s: directive %r is '
'already registered, it will be overridden',
@ -731,7 +682,7 @@ class Sphinx(object):
def add_role(self, name, role):
# 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:
logger.warning('while setting up extension %s: role %r is '
'already registered, it will be overridden',
@ -743,7 +694,7 @@ class Sphinx(object):
# type: (unicode, Any) -> None
# don't use roles.register_generic_role because it uses
# 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:
logger.warning('while setting up extension %s: role %r is '
'already registered, it will be overridden',
@ -754,14 +705,14 @@ class Sphinx(object):
def add_domain(self, domain):
# type: (Type[Domain]) -> None
self.debug('[app] adding domain: %r', domain)
logger.debug('[app] adding domain: %r', domain)
if domain.name in self.domains:
raise ExtensionError('domain %s already registered' % domain.name)
self.domains[domain.name] = domain
def override_domain(self, domain):
# 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:
raise ExtensionError('domain %s not yet registered' % domain.name)
if not issubclass(domain, self.domains[domain.name]):
@ -772,8 +723,8 @@ class Sphinx(object):
def add_directive_to_domain(self, domain, name, obj,
content=None, arguments=None, **options):
# type: (unicode, unicode, Any, unicode, Any, Any) -> None
self.debug('[app] adding directive to domain: %r',
(domain, name, obj, content, arguments, options))
logger.debug('[app] adding directive to domain: %r',
(domain, name, obj, content, arguments, options))
if domain not in self.domains:
raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].directives[name] = \
@ -781,14 +732,14 @@ class Sphinx(object):
def add_role_to_domain(self, domain, name, role):
# 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:
raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].roles[name] = role
def add_index_to_domain(self, domain, index):
# 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:
raise ExtensionError('domain %s not yet registered' % domain)
self.domains[domain].indices.append(index)
@ -797,9 +748,9 @@ class Sphinx(object):
parse_node=None, ref_nodeclass=None, objname='',
doc_field_types=[]):
# type: (unicode, unicode, unicode, Callable, nodes.Node, unicode, List) -> None
self.debug('[app] adding object type: %r',
(directivename, rolename, indextemplate, parse_node,
ref_nodeclass, objname, doc_field_types))
logger.debug('[app] adding object type: %r',
(directivename, rolename, indextemplate, parse_node,
ref_nodeclass, objname, doc_field_types))
StandardDomain.object_types[directivename] = \
ObjType(objname or directivename, rolename)
# create a subclass of GenericObject as the new directive
@ -817,9 +768,9 @@ class Sphinx(object):
def add_crossref_type(self, directivename, rolename, indextemplate='',
ref_nodeclass=None, objname=''):
# type: (unicode, unicode, unicode, nodes.Node, unicode) -> None
self.debug('[app] adding crossref type: %r',
(directivename, rolename, indextemplate, ref_nodeclass,
objname))
logger.debug('[app] adding crossref type: %r',
(directivename, rolename, indextemplate, ref_nodeclass,
objname))
StandardDomain.object_types[directivename] = \
ObjType(objname or directivename, rolename)
# create a subclass of Target as the new directive
@ -831,12 +782,12 @@ class Sphinx(object):
def add_transform(self, transform):
# type: (Transform) -> None
self.debug('[app] adding transform: %r', transform)
logger.debug('[app] adding transform: %r', transform)
SphinxStandaloneReader.transforms.append(transform)
def add_javascript(self, filename):
# type: (unicode) -> None
self.debug('[app] adding javascript: %r', filename)
logger.debug('[app] adding javascript: %r', filename)
from sphinx.builders.html import StandaloneHTMLBuilder
if '://' in filename:
StandaloneHTMLBuilder.script_files.append(filename)
@ -846,7 +797,7 @@ class Sphinx(object):
def add_stylesheet(self, filename):
# type: (unicode) -> None
self.debug('[app] adding stylesheet: %r', filename)
logger.debug('[app] adding stylesheet: %r', filename)
from sphinx.builders.html import StandaloneHTMLBuilder
if '://' in filename:
StandaloneHTMLBuilder.css_files.append(filename)
@ -856,12 +807,12 @@ class Sphinx(object):
def add_latex_package(self, packagename, options=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))
def add_lexer(self, alias, lexer):
# 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
if lexers is None:
return
@ -869,27 +820,27 @@ class Sphinx(object):
def add_autodocumenter(self, cls):
# type: (Any) -> None
self.debug('[app] adding autodocumenter: %r', cls)
logger.debug('[app] adding autodocumenter: %r', cls)
from sphinx.ext import autodoc
autodoc.add_documenter(cls)
self.add_directive('auto' + cls.objtype, autodoc.AutoDirective)
def add_autodoc_attrgetter(self, type, getter):
# 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
autodoc.AutoDirective._special_attrgetters[type] = getter
def add_search_language(self, cls):
# 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
assert issubclass(cls, SearchLanguage)
languages[cls.lang] = cls
def add_source_parser(self, suffix, parser):
# 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:
logger.warning('while setting up extension %s: source_parser for %r is '
'already registered, it will be overridden',

View File

@ -40,6 +40,9 @@ if False:
from sphinx.util.tags import Tags # NOQA
logger = logging.getLogger(__name__)
class Builder(object):
"""
Builds target formats from the reST sources.
@ -180,7 +183,7 @@ class Builder(object):
def cat2relpath(cat):
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(
catalogs, 'writing output... ', darkgreen, len(catalogs),
cat2relpath):
@ -281,7 +284,7 @@ class Builder(object):
First updates the environment, and then calls :meth:`write`.
"""
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
with logging.pending_logging():
@ -289,29 +292,29 @@ class Builder(object):
self.doctreedir, self.app))
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):
updated_docnames.add(docname)
outdated = len(updated_docnames) - doccount
if outdated:
self.info('%d found' % outdated)
logger.info('%d found' % outdated)
else:
self.info('none found')
logger.info('none found')
if updated_docnames:
# save the environment
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.info('done')
logger.info('done')
# global actions
self.info(bold('checking consistency... '), nonl=True)
logger.info(bold('checking consistency... '), nonl=True)
self.env.check_consistency()
self.info('done')
logger.info('done')
else:
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
# filter "docnames" (list of outdated files) by the updated
@ -358,7 +361,7 @@ class Builder(object):
docnames = set(build_docnames) | set(updated_docnames)
else:
docnames = set(build_docnames)
self.app.debug('docnames to write: %s', ', '.join(sorted(docnames)))
logger.debug('docnames to write: %s', ', '.join(sorted(docnames)))
# add all toctree-containing files that may have changed
for docname in list(docnames):
@ -367,9 +370,9 @@ class Builder(object):
docnames.add(tocdocname)
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.info('done')
logger.info('done')
warnings = [] # type: List[Tuple[Tuple, Dict]]
if self.parallel_ok:
@ -425,7 +428,7 @@ class Builder(object):
tasks.add_task(write_process, arg, add_warnings)
# make sure all threads have finished
self.info(bold('waiting for workers...'))
logger.info(bold('waiting for workers...'))
tasks.join()
for warning, kwargs in warnings:

View File

@ -18,6 +18,7 @@ import shlex
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.config import string_classes
from sphinx.util import logging
from sphinx.util.osutil import copyfile, ensuredir, make_filename
from sphinx.util.console import bold # type: ignore
from sphinx.util.fileutil import copy_asset
@ -33,6 +34,9 @@ if False:
from typing import Any # NOQA
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
# Use plistlib.dump in 3.4 and above
try:
write_plist = plistlib.dump # type: ignore
@ -118,13 +122,13 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
target_dir = self.outdir
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 + ['**/.*'])
copy_asset(source_dir, target_dir, excluded,
context=self.globalcontext, renderer=self.templates)
self.info('done')
logger.info('done')
def build_helpbook(self):
# type: () -> None
@ -165,20 +169,20 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
if self.config.applehelp_remote_url is not None:
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:
write_plist(info_plist, f)
self.info('done')
logger.info('done')
# Copy the icon, if one is supplied
if self.config.applehelp_icon:
self.info(bold('copying icon... '), nonl=True)
logger.info(bold('copying icon... '), nonl=True)
try:
copyfile(path.join(self.srcdir, self.config.applehelp_icon),
path.join(resources_dir, info_plist['HPDBookIconPath']))
self.info('done')
logger.info('done')
except Exception as err:
self.warn('cannot copy icon file %r: %s' %
(path.join(self.srcdir, self.config.applehelp_icon),
@ -186,16 +190,16 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
del info_plist['HPDBookIconPath']
# 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:
f.write(access_page_template % {
'toc': htmlescape(toc, quote=True),
'title': htmlescape(self.config.applehelp_title)
})
self.info('done')
logger.info('done')
# Generate the help index
self.info(bold('generating help index... '), nonl=True)
logger.info(bold('generating help index... '), nonl=True)
args = [
self.config.applehelp_indexer_path,
@ -217,7 +221,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
args += ['-l', self.config.applehelp_locale]
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'
% (' '.join([pipes.quote(arg) for arg in args])))
@ -232,13 +236,13 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
if p.returncode != 0:
raise AppleHelpIndexerFailed(output)
else:
self.info('done')
logger.info('done')
except OSError:
raise AppleHelpIndexerFailed('Command not found: %s' % args[0])
# If we've been asked to, sign the bundle
if self.config.applehelp_codesign_identity:
self.info(bold('signing help book... '), nonl=True)
logger.info(bold('signing help book... '), nonl=True)
args = [
self.config.applehelp_codesign_path,
@ -251,7 +255,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
args.append(self.bundle_path)
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'
% (' '.join([pipes.quote(arg) for arg in args])))
@ -266,7 +270,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
if p.returncode != 0:
raise AppleHelpCodeSigningFailed(output)
else:
self.info('done')
logger.info('done')
except OSError:
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.theming import Theme
from sphinx.builders import Builder
from sphinx.util import logging
from sphinx.util.osutil import ensuredir, os_path
from sphinx.util.console import bold # type: ignore
from sphinx.util.fileutil import copy_asset_file
@ -29,6 +30,9 @@ if False:
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
class ChangesBuilder(Builder):
"""
Write a summary with all versionadded/changed directives.
@ -59,9 +63,9 @@ class ChangesBuilder(Builder):
apichanges = [] # type: List[Tuple[unicode, unicode, int]]
otherchanges = {} # type: Dict[Tuple[unicode, unicode], List[Tuple[unicode, unicode, int]]] # NOQA
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
self.info(bold('writing summary file...'))
logger.info(bold('writing summary file...'))
for type, docname, lineno, module, descname, content in \
self.env.versionchanges[version]:
if isinstance(descname, tuple):
@ -125,7 +129,7 @@ class ChangesBuilder(Builder):
break
return line
self.info(bold('copying source files...'))
logger.info(bold('copying source files...'))
for docname in self.env.all_docs:
with codecs.open(self.env.doc2path(docname), 'r', # type: ignore
self.env.config.source_encoding) as f:

View File

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

View File

@ -29,6 +29,7 @@ from docutils import nodes
from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.util import logging
from sphinx.util.osutil import ensuredir, copyfile, make_filename, EEXIST
from sphinx.util.smartypants import sphinx_smarty_pants as ssp
from sphinx.util.console import brown # type: ignore
@ -39,6 +40,9 @@ if False:
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
# (Fragment) templates from which the metainfo files content.opf, toc.ncx,
# mimetype, and META-INF/container.xml are created.
# 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):
# type: (unicode, unicode) -> None
"""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
f.write(self.mimetype_template)
def build_container(self, outdir, outname):
# type: (unicode, unicode) -> None
"""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)
try:
os.mkdir(path.dirname(fn))
@ -589,7 +593,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
"""Write the metainfo file content.opf It contains bibliographic data,
a file list and the spine (the reading order).
"""
self.info('writing %s file...' % outname)
logger.info('writing %s file...' % outname)
# files
if not outdir.endswith(os.sep):
@ -800,7 +804,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
def build_toc(self, outdir, outname):
# type: (unicode, unicode) -> None
"""Write the metainfo file toc.ncx."""
self.info('writing %s file...' % outname)
logger.info('writing %s file...' % outname)
if self.config.epub_tocscope == 'default':
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
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.extend(self.files)
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.builders.epub import EpubBuilder
from sphinx.util import logging
logger = logging.getLogger(__name__)
# (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):
"""Write the metainfo file nav.xhtml."""
self.info('writing %s file...' % outname)
logger.info('writing %s file...' % outname)
if self.config.epub_tocscope == 'default':
doctree = self.env.get_and_resolve_doctree(

View File

@ -21,7 +21,7 @@ from uuid import uuid4
from six import iteritems
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.nodes import extract_messages, traverse_translatable_index
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.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
POHEADER = r"""
# SOME DESCRIPTIVE TITLE.
# Copyright (C) %(copyright)s
@ -216,8 +219,8 @@ class MessageCatalogBuilder(I18nBuilder):
def _extract_from_template(self):
# type: () -> None
files = self._collect_templates()
self.info(bold('building [%s]: ' % self.name), nonl=1)
self.info('targets for %d template files' % len(files))
logger.info(bold('building [%s]: ' % self.name), nonl=1)
logger.info('targets for %d template files' % len(files))
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 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.osutil import SEP, os_path, relative_uri, ensuredir, \
movefile, copyfile
@ -57,6 +57,8 @@ INVENTORY_FILENAME = 'objects.inv'
#: the filename for the "last build" file (for serializing builders)
LAST_BUILD_FILENAME = 'last_build'
logger = logging.getLogger(__name__)
def get_stable_hash(obj):
# type: (Any) -> unicode
@ -502,7 +504,7 @@ class StandaloneHTMLBuilder(Builder):
def gen_indices(self):
# type: () -> None
self.info(bold('generating indices...'), nonl=1)
logger.info(bold('generating indices...'), nonl=1)
# the global general index
if self.use_index:
@ -511,7 +513,7 @@ class StandaloneHTMLBuilder(Builder):
# the global domain-specific indices
self.write_domain_indices()
self.info()
logger.info('')
def gen_additional_pages(self):
# type: () -> None
@ -520,25 +522,25 @@ class StandaloneHTMLBuilder(Builder):
for pagename, context, template in pagelist:
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
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)
# the search page
if self.search:
self.info(' search', nonl=1)
logger.info(' search', nonl=1)
self.handle_page('search', {}, 'search.html')
# the opensearch xml file
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')
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
self.info()
logger.info('')
def write_genindex(self):
# type: () -> None
@ -555,7 +557,7 @@ class StandaloneHTMLBuilder(Builder):
genindexcounts = indexcounts,
split_index = self.config.html_split_index,
)
self.info(' genindex', nonl=1)
logger.info(' genindex', nonl=1)
if self.config.html_split_index:
self.handle_page('genindex', genindexcontext,
@ -578,7 +580,7 @@ class StandaloneHTMLBuilder(Builder):
content = content,
collapse_index = collapse,
)
self.info(' ' + indexname, nonl=1)
logger.info(' ' + indexname, nonl=1)
self.handle_page(indexname, indexcontext, 'domainindex.html')
def copy_image_files(self):
@ -618,7 +620,7 @@ class StandaloneHTMLBuilder(Builder):
def copy_static_files(self):
# type: () -> None
# 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'))
# first, create pygments style file
with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f:
@ -674,12 +676,12 @@ class StandaloneHTMLBuilder(Builder):
elif not path.isfile(icontarget):
copyfile(path.join(self.confdir, self.config.html_favicon),
icontarget)
self.info('done')
logger.info('done')
def copy_extra_files(self):
# type: () -> None
# 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)
for extra_path in self.config.html_extra_path:
@ -689,7 +691,7 @@ class StandaloneHTMLBuilder(Builder):
continue
copy_asset(entry, self.outdir, excluded)
self.info('done')
logger.info('done')
def write_buildinfo(self):
# type: () -> None
@ -890,7 +892,7 @@ class StandaloneHTMLBuilder(Builder):
def dump_inventory(self):
# 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:
f.write((u'# Sphinx inventory version 2\n'
u'# Project: %s\n'
@ -913,11 +915,11 @@ class StandaloneHTMLBuilder(Builder):
(u'%s %s:%s %s %s %s\n' % (name, domainname, type,
prio, uri, dispname)).encode('utf-8')))
f.write(compressor.flush())
self.info('done')
logger.info('done')
def dump_search_index(self):
# type: () -> None
self.info(
logger.info(
bold('dumping search index in %s ... ' % self.indexer.label()),
nonl=True)
self.indexer.prune(self.env.all_docs)
@ -931,7 +933,7 @@ class StandaloneHTMLBuilder(Builder):
with f:
self.indexer.dump(f, self.indexer_format) # type: ignore
movefile(searchindexfn + '.tmp', searchindexfn)
self.info('done')
logger.info('done')
class DirectoryHTMLBuilder(StandaloneHTMLBuilder):
@ -1097,36 +1099,36 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
# type: (Any) -> None
docnames = self.env.all_docs
self.info(bold('preparing documents... '), nonl=True)
logger.info(bold('preparing documents... '), nonl=True)
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()
self.env.toc_secnumbers = self.assemble_toc_secnumbers()
self.env.toc_fignumbers = self.assemble_toc_fignumbers()
self.info()
self.info(bold('writing... '), nonl=True)
logger.info('')
logger.info(bold('writing... '), nonl=True)
self.write_doc_serialized(self.config.master_doc, doctree)
self.write_doc(self.config.master_doc, doctree)
self.info('done')
logger.info('done')
def finish(self):
# type: () -> None
# 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
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)
if self.config.html_use_opensearch:
self.info(' opensearch', nonl=1)
logger.info(' opensearch', nonl=1)
fn = path.join(self.outdir, '_static', 'opensearch.xml')
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
self.info()
logger.info('')
self.copy_image_files()
self.copy_download_files()

View File

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

View File

@ -20,7 +20,7 @@ from docutils.utils import new_document
from docutils.frontend import OptionParser
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.errors import SphinxError
from sphinx.locale import _
@ -38,6 +38,9 @@ if False:
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
class LaTeXBuilder(Builder):
"""
Builds LaTeX output to create PDF.
@ -119,7 +122,7 @@ class LaTeXBuilder(Builder):
destination = FileOutput(
destination_path=path.join(self.outdir, targetname),
encoding='utf-8')
self.info("processing " + targetname + "... ", nonl=1)
logger.info("processing " + targetname + "... ", nonl=1)
toctrees = self.env.get_doctree(docname).traverse(addnodes.toctree)
if toctrees:
if toctrees[0].get('maxdepth') > 0:
@ -133,7 +136,7 @@ class LaTeXBuilder(Builder):
appendices=((docclass != 'howto') and self.config.latex_appendices or []))
doctree['tocdepth'] = tocdepth
self.post_process_images(doctree)
self.info("writing... ", nonl=1)
logger.info("writing... ", nonl=1)
doctree.settings = docsettings
doctree.settings.author = author
doctree.settings.title = title
@ -141,7 +144,7 @@ class LaTeXBuilder(Builder):
doctree.settings.docname = docname
doctree.settings.docclass = docclass
docwriter.write(doctree, destination)
self.info("done")
logger.info("done")
def get_contentsname(self, indexfile):
# type: (unicode) -> unicode
@ -157,7 +160,7 @@ class LaTeXBuilder(Builder):
def assemble_doctree(self, indexfile, toctree_only, appendices):
# type: (unicode, bool, List[unicode]) -> nodes.Node
self.docnames = set([indexfile] + appendices)
self.info(darkgreen(indexfile) + " ", nonl=1)
logger.info(darkgreen(indexfile) + " ", nonl=1)
tree = self.env.get_doctree(indexfile)
tree['docname'] = indexfile
if toctree_only:
@ -178,8 +181,8 @@ class LaTeXBuilder(Builder):
appendix = self.env.get_doctree(docname)
appendix['docname'] = docname
largetree.append(appendix)
self.info()
self.info("resolving references...")
logger.info('')
logger.info("resolving references...")
self.env.resolve_references(largetree, indexfile, self)
# resolve :ref:s to distant tex files -- we can't add a cross-reference,
# but append the document name
@ -202,16 +205,16 @@ class LaTeXBuilder(Builder):
# type: () -> None
# copy image files
if self.images:
self.info(bold('copying images...'), nonl=1)
logger.info(bold('copying images...'), nonl=1)
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),
path.join(self.outdir, dest))
self.info()
logger.info('')
# copy TeX support files from texinputs
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')
for filename in os.listdir(staticdirname):
if not filename.startswith('.'):
@ -220,11 +223,11 @@ class LaTeXBuilder(Builder):
# copy 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:
self.info(' '+filename, nonl=1)
logger.info(' '+filename, nonl=1)
copy_asset_file(path.join(self.confdir, filename), self.outdir)
self.info()
logger.info('')
# the logo is handled differently
if self.config.latex_logo:
@ -232,7 +235,7 @@ class LaTeXBuilder(Builder):
raise SphinxError('logo file %r does not exist' % self.config.latex_logo)
else:
copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir)
self.info('done')
logger.info('done')
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.urllib.parse import unquote
from six.moves.html_parser import HTMLParser
from docutils import nodes
# 2015-06-25 barry@python.org. This exception was deprecated in Python 3.3 and
@ -33,7 +32,7 @@ except ImportError:
pass
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
purple, red, darkgreen, darkgray, darkred, turquoise
)
@ -46,6 +45,9 @@ if False:
from sphinx.util.requests.requests import Response # NOQA
logger = logging.getLogger(__name__)
class AnchorCheckParser(HTMLParser):
"""Specialized HTML parser that looks for a specific anchor."""
@ -231,24 +233,24 @@ class CheckExternalLinksBuilder(Builder):
if status == 'working' and info == 'old':
return
if lineno:
self.info('(line %4d) ' % lineno, nonl=1)
logger.info('(line %4d) ' % lineno, nonl=1)
if status == 'ignored':
if info:
self.info(darkgray('-ignored- ') + uri + ': ' + info)
logger.info(darkgray('-ignored- ') + uri + ': ' + info)
else:
self.info(darkgray('-ignored- ') + uri)
logger.info(darkgray('-ignored- ') + uri)
elif status == 'local':
self.info(darkgray('-local- ') + uri)
logger.info(darkgray('-local- ') + uri)
self.write_entry('local', docname, lineno, uri)
elif status == 'working':
self.info(darkgreen('ok ') + uri + info)
logger.info(darkgreen('ok ') + uri + info)
elif status == 'broken':
self.write_entry('broken', docname, lineno, uri + ': ' + info)
if self.app.quiet or self.app.warningiserror:
self.warn('broken link: %s (%s)' % (uri, info),
'%s:%s' % (self.env.doc2path(docname), lineno))
else:
self.info(red('broken ') + uri + red(' - ' + info))
logger.info(red('broken ') + uri + red(' - ' + info))
elif status == 'redirected':
text, color = {
301: ('permanently', darkred),
@ -259,7 +261,7 @@ class CheckExternalLinksBuilder(Builder):
}[code]
self.write_entry('redirected ' + text, docname, lineno,
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):
# type: (unicode, unicode) -> unicode
@ -275,7 +277,7 @@ class CheckExternalLinksBuilder(Builder):
def write_doc(self, docname, doctree):
# type: (unicode, nodes.Node) -> None
self.info()
logger.info('')
n = 0
for node in doctree.traverse(nodes.reference):
if 'refuri' not in node:

View File

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

View File

@ -21,7 +21,7 @@ from docutils import nodes
from sphinx import addnodes
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.pycompat import htmlescape
@ -31,6 +31,9 @@ if False:
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
_idpattern = re.compile(
r'(?P<title>.+) (\((class in )?(?P<id>[\w\.]+)( (?P<descr>\w+))?\))$')
@ -138,7 +141,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
def build_qhp(self, outdir, outname):
# type: (unicode, unicode) -> None
self.info('writing project file...')
logger.info('writing project file...')
# sections
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))
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
f.write(collection_template % { # type: ignore
'outname': htmlescape(outname),

View File

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

View File

@ -33,7 +33,7 @@ from docutils.frontend import OptionParser
from sphinx import addnodes
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, \
process_only_nodes
from sphinx.util.osutil import SEP, getcwd, fs_encoding, ensuredir
@ -60,6 +60,8 @@ if False:
from sphinx.domains import Domain # NOQA
from sphinx.environment.managers import EnvironmentManager # NOQA
logger = logging.getLogger(__name__)
default_settings = {
'embed_stylesheet': False,
'cloak_email_addresses': True,
@ -553,7 +555,7 @@ class BuildEnvironment(object):
# this cache also needs to be updated every time
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)
@ -569,7 +571,7 @@ class BuildEnvironment(object):
msg += '%s added, %s changed, %s removed' % (len(added), len(changed),
len(removed))
app.info(msg)
logger.info(msg)
self.app = app
@ -664,7 +666,7 @@ class BuildEnvironment(object):
tasks.add_task(read_process, chunk, merge)
# make sure all threads have finished
app.info(bold('waiting for workers...'))
logger.info(bold('waiting for workers...'))
tasks.join()
for warning, kwargs in warnings:

View File

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

View File

@ -69,7 +69,7 @@ from docutils import nodes
import sphinx
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.ext.autodoc import Options
@ -81,6 +81,8 @@ if False:
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc import Documenter # NOQA
logger = logging.getLogger(__name__)
# -- autosummary_toc node ------------------------------------------------------
@ -305,8 +307,7 @@ class Autosummary(Directive):
# be cached anyway)
documenter.analyzer.find_attr_docs()
except PycodeError as err:
documenter.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
documenter.analyzer = None

View File

@ -25,7 +25,7 @@ from docutils.parsers.rst import Directive, directives
import sphinx
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.console import bold # type: ignore
from sphinx.util.osutil import fs_encoding
@ -35,6 +35,8 @@ if False:
from typing import Any, Callable, IO, Iterable, Sequence, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
blankline_re = re.compile(r'^\s*<BLANKLINE>', 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):
# type: (unicode) -> None
self.info(text, nonl=True)
logger.info(text, nonl=True)
self.outfile.write(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:
self.warn(text)
else:
self.info(text, nonl=True)
logger.info(text, nonl=True)
if isinstance(text, binary_type):
text = force_decode(text, None)
self.outfile.write(text)
@ -311,7 +313,7 @@ Doctest summary
if build_docnames is None:
build_docnames = sorted(self.env.all_docs)
self.info(bold('running tests...'))
logger.info(bold('running tests...'))
for docname in build_docnames:
# no need to resolve the doctree
doctree = self.env.get_doctree(docname)

View File

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

View File

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

View File

@ -15,9 +15,13 @@ from docutils.transforms.parts import ContentsFilter
from sphinx import addnodes
from sphinx.locale import _
from sphinx.util import logging
from sphinx.util.i18n import format_date
from sphinx.util.nodes import apply_source_workaround
logger = logging.getLogger(__name__)
default_substitutions = set([
'version',
'release',
@ -215,7 +219,7 @@ class FilterSystemMessages(Transform):
filterlevel = env.config.keep_warnings and 2 or 5
for node in self.document.traverse(nodes.system_message):
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)

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 sphinx.errors import PycodeError, SphinxParallelError, ExtensionError
from sphinx.util import logging
from sphinx.util.console import strip_colors
from sphinx.util.fileutil import copy_asset_file
from sphinx.util.osutil import fs_encoding
@ -46,6 +47,9 @@ if False:
# For type annotation
from typing import Any, Callable, Iterable, Pattern, Sequence, Tuple # NOQA
logger = logging.getLogger(__name__)
# Generally useful regular expressions.
ws_re = re.compile(r'\s+') # type: Pattern
url_re = re.compile(r'(?P<schema>.+)://.*') # type: Pattern
@ -532,3 +536,12 @@ def split_docinfo(text):
return '', result[0]
else:
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)