diff --git a/CHANGES b/CHANGES index c6bec7759bb..c501a879daf 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,7 @@ Bugs fixed * #4493: recommonmark raises AttributeError if AutoStructify enabled * #4209: intersphinx: In link title, "v" should be optional if target has no version +* #4230: slowdown in writing pages with sphinx 1.6 Testing -------- diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 2b2473e6c60..bb6818af7a8 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -23,7 +23,7 @@ from docutils.frontend import OptionParser from docutils.io import DocTreeInput, StringOutput from docutils.readers.doctree import Reader as DoctreeReader -from docutils.utils import new_document, relative_path +from docutils.utils import relative_path from six import iteritems, text_type, string_types from six.moves import cPickle as pickle @@ -41,7 +41,7 @@ from sphinx.theming import HTMLThemeFactory from sphinx.util import jsonimpl, logging, status_iterator from sphinx.util.console import bold, darkgreen # type: ignore -from sphinx.util.docutils import is_html5_writer_available +from sphinx.util.docutils import is_html5_writer_available, new_document from sphinx.util.fileutil import copy_asset from sphinx.util.i18n import format_date from sphinx.util.inventory import InventoryFile diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py index 08149be7503..c66d00d4f8a 100644 --- a/sphinx/builders/latex.py +++ b/sphinx/builders/latex.py @@ -15,7 +15,6 @@ from docutils import nodes from docutils.frontend import OptionParser from docutils.io import FileOutput -from docutils.utils import new_document from six import text_type from sphinx import package_dir, addnodes, highlighting @@ -27,6 +26,7 @@ from sphinx.locale import _ from sphinx.util import texescape, logging, status_iterator from sphinx.util.console import bold, darkgreen # type: ignore +from sphinx.util.docutils import new_document from sphinx.util.fileutil import copy_asset_file from sphinx.util.nodes import inline_all_toctrees from sphinx.util.osutil import SEP, make_filename diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index 651e2cfea24..c9a95a5fc29 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -15,7 +15,6 @@ from docutils import nodes from docutils.frontend import OptionParser from docutils.io import FileOutput -from docutils.utils import new_document from sphinx import addnodes from sphinx.builders import Builder @@ -25,6 +24,7 @@ from sphinx.util import logging from sphinx.util import status_iterator from sphinx.util.console import bold, darkgreen # type: ignore +from sphinx.util.docutils import new_document from sphinx.util.fileutil import copy_asset_file from sphinx.util.nodes import inline_all_toctrees from sphinx.util.osutil import SEP, make_filename diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index 8f70fc537c4..a2e92223d27 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -15,12 +15,13 @@ from docutils.transforms import Transform, Transformer from docutils.transforms.parts import ContentsFilter from docutils.transforms.universal import SmartQuotes -from docutils.utils import new_document, normalize_language_tag +from docutils.utils import normalize_language_tag from docutils.utils.smartquotes import smartchars from sphinx import addnodes from sphinx.locale import _ from sphinx.util import logging +from sphinx.util.docutils import new_document from sphinx.util.i18n import format_date from sphinx.util.nodes import apply_source_workaround, is_smartquotable diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 88c0b34e71b..50483d3f121 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -17,6 +17,7 @@ from distutils.version import LooseVersion import docutils +from docutils import nodes from docutils.languages import get_language from docutils.parsers.rst import directives, roles, convert_directive_function from docutils.statemachine import StateMachine @@ -32,7 +33,6 @@ if False: # For type annotation from typing import Any, Callable, Generator, Iterator, List, Tuple # NOQA - from docutils import nodes # NOQA from docutils.statemachine import State, ViewList # NOQA from sphinx.environment import BuildEnvironment # NOQA from sphinx.io import SphinxFileInput # NOQA @@ -221,3 +221,30 @@ def switch_source_input(state, content): finally: # restore the method state.memo.reporter.get_source_and_line = get_source_and_line + + +# cache a vanilla instance of nodes.document +# Used in new_document() function +__document_cache__ = None # type: nodes.document + + +def new_document(source_path, settings=None): + # type: (unicode, Any) -> nodes.document + """Return a new empty document object. This is an alternative of docutils'. + + This is a simple wrapper for ``docutils.utils.new_document()``. It + caches the result of docutils' and use it on second call for instanciation. + This makes an instantiation of document nodes much faster. + """ + global __document_cache__ + if __document_cache__ is None: + __document_cache__ = docutils.utils.new_document(source_path) + + if settings is None: + # Make a copy of ``settings`` from cache to accelerate instansiation + settings = copy(__document_cache__.settings) + + # Create a new instance of nodes.document using cached reporter + document = nodes.document(settings, __document_cache__.reporter, source=source_path) + document.note_source(source_path, -1) + return document