Add app.is_parallel_allowed()

This commit is contained in:
Takeshi KOMIYA 2017-12-30 00:54:55 +09:00
parent 54699dd263
commit 1d3362425b
9 changed files with 91 additions and 23 deletions

View File

@ -19,7 +19,7 @@ import posixpath
from os import path from os import path
from collections import deque from collections import deque
from six import iteritems from six import iteritems, itervalues
from six.moves import cStringIO from six.moves import cStringIO
from docutils import nodes from docutils import nodes
@ -673,6 +673,34 @@ class Sphinx(object):
logger.debug('[app] adding HTML theme: %r, %r', name, theme_path) logger.debug('[app] adding HTML theme: %r, %r', name, theme_path)
self.html_themes[name] = theme_path self.html_themes[name] = theme_path
# ---- other methods -------------------------------------------------
def is_parallel_allowed(self, typ):
# type: (unicode) -> bool
"""Check parallel processing is allowed or not.
``typ`` is a type of processing; ``'read'`` or ``'write'``.
"""
if typ == 'read':
attrname = 'parallel_read_safe'
elif typ == 'write':
attrname = 'parallel_write_safe'
else:
raise ValueError('parallel type %s is not supported' % typ)
for ext in itervalues(self.extensions):
allowed = getattr(ext, attrname, None)
if allowed is None:
logger.warning(__("the %s extension does not declare if it is safe "
"for parallel %sing, assuming it isn't - please "
"ask the extension author to check and make it "
"explicit"), ext.name, typ)
logger.warning('doing serial %s', typ)
return False
elif not allowed:
return False
return True
class TemplateBridge(object): class TemplateBridge(object):
""" """

View File

@ -371,15 +371,10 @@ class Builder(object):
docnames = set(docnames) & self.env.found_docs docnames = set(docnames) & self.env.found_docs
# determine if we can write in parallel # determine if we can write in parallel
self.parallel_ok = False
if parallel_available and self.app.parallel > 1 and self.allow_parallel: if parallel_available and self.app.parallel > 1 and self.allow_parallel:
self.parallel_ok = True self.parallel_ok = self.app.is_parallel_allowed('write')
for extension in itervalues(self.app.extensions): else:
if not extension.parallel_write_safe: self.parallel_ok = False
logger.warning('the %s extension is not safe for parallel '
'writing, doing serial write', extension.name)
self.parallel_ok = False
break
# create a task executor to use for misc. "finish-up" tasks # create a task executor to use for misc. "finish-up" tasks
# if self.parallel_ok: # if self.parallel_ok:

View File

@ -558,21 +558,10 @@ class BuildEnvironment(object):
self.app.emit('env-before-read-docs', self, docnames) self.app.emit('env-before-read-docs', self, docnames)
# check if we should do parallel or serial read # check if we should do parallel or serial read
par_ok = False
if parallel_available and len(docnames) > 5 and self.app.parallel > 1: if parallel_available and len(docnames) > 5 and self.app.parallel > 1:
for ext in itervalues(self.app.extensions): par_ok = self.app.is_parallel_allowed('read')
if ext.parallel_read_safe is None: else:
logger.warning(__('the %s extension does not declare if it is safe ' par_ok = False
'for parallel reading, assuming it isn\'t - please '
'ask the extension author to check and make it '
'explicit'), ext.name)
logger.warning('doing serial read')
break
elif ext.parallel_read_safe is False:
break
else:
# all extensions support parallel-read
par_ok = True
if par_ok: if par_ok:
self._read_parallel(docnames, self.app, nproc=self.app.parallel) self._read_parallel(docnames, self.app, nproc=self.app.parallel)

View File

@ -0,0 +1,4 @@
import os
import sys
sys.path.insert(0, os.path.abspath('.'))

View File

@ -0,0 +1,4 @@
def setup(app):
return {
'parallel_read_safe': True
}

View File

@ -0,0 +1,4 @@
def setup(app):
return {
'parallel_read_safe': False
}

View File

@ -0,0 +1,4 @@
def setup(app):
return {
'parallel_write_safe': True,
}

View File

@ -0,0 +1,4 @@
def setup(app):
return {
'parallel_write_safe': False
}

View File

@ -12,6 +12,7 @@ from docutils import nodes
from sphinx.application import ExtensionError from sphinx.application import ExtensionError
from sphinx.domains import Domain from sphinx.domains import Domain
from sphinx.util import logging
from sphinx.testing.util import strip_escseq from sphinx.testing.util import strip_escseq
import pytest import pytest
@ -86,3 +87,38 @@ def test_add_source_parser(app, status, warning):
assert set(app.registry.get_source_parsers().keys()) == set(['*', '.md', '.test']) assert set(app.registry.get_source_parsers().keys()) == set(['*', '.md', '.test'])
assert app.registry.get_source_parsers()['.md'].__name__ == 'DummyMarkdownParser' assert app.registry.get_source_parsers()['.md'].__name__ == 'DummyMarkdownParser'
assert app.registry.get_source_parsers()['.test'].__name__ == 'TestSourceParser' assert app.registry.get_source_parsers()['.test'].__name__ == 'TestSourceParser'
@pytest.mark.sphinx(testroot='extensions')
def test_add_is_parallel_allowed(app, status, warning):
logging.setup(app, status, warning)
assert app.is_parallel_allowed('read') is True
assert app.is_parallel_allowed('write') is True
assert warning.getvalue() == ''
app.setup_extension('read_parallel')
assert app.is_parallel_allowed('read') is True
assert app.is_parallel_allowed('write') is True
assert warning.getvalue() == ''
app.extensions.pop('read_parallel')
app.setup_extension('write_parallel')
assert app.is_parallel_allowed('read') is False
assert app.is_parallel_allowed('write') is True
assert 'the write_parallel extension does not declare' in warning.getvalue()
app.extensions.pop('write_parallel')
warning.truncate(0) # reset warnings
app.setup_extension('read_serial')
assert app.is_parallel_allowed('read') is False
assert app.is_parallel_allowed('write') is True
assert warning.getvalue() == ''
app.extensions.pop('read_serial')
app.setup_extension('write_serial')
assert app.is_parallel_allowed('read') is False
assert app.is_parallel_allowed('write') is False
assert 'the write_serial extension does not declare' in warning.getvalue()
app.extensions.pop('write_serial')
warning.truncate(0) # reset warnings