diff --git a/sphinx/application.py b/sphinx/application.py index 95e1ff17d..181ef1d95 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -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', diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index b8baf7792..9dc757cd4 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -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: diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py index 3c2782802..b0c5c66b1 100644 --- a/sphinx/builders/applehelp.py +++ b/sphinx/builders/applehelp.py @@ -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]) diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index de9e95bf1..d1b908e3d 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -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: diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py index f1ed3a495..af8bcfeed 100644 --- a/sphinx/builders/devhelp.py +++ b/sphinx/builders/devhelp.py @@ -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', diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 5d4686af6..97c736d9f 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -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 diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index 5e0663a08..55434a499 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -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( diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index ced63e8f5..a38c9eca4 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -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 diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 31ee0a371..b4f4d7fd3 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -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() diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 79268ab74..5f94460c8 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -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('