diff options
46 files changed, 404 insertions, 159 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 146f3b6bc..0fa6b61fe 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -15,7 +15,7 @@ Steps to reproduce the behavior: ``` <Paste your command-line here which cause the problem> -$ git clone htps://github.com/.../some_project +$ git clone https://github.com/.../some_project $ cd some_project $ pip install -r requirements.txt $ cd docs @@ -13,6 +13,24 @@ Incompatible changes Deprecated ---------- +* ``sphinx.builders.latex.LaTeXBuilder.apply_transforms()`` +* ``sphinx.directives.Acks`` +* ``sphinx.directives.Author`` +* ``sphinx.directives.Centered`` +* ``sphinx.directives.Class`` +* ``sphinx.directives.CodeBlock`` +* ``sphinx.directives.Figure`` +* ``sphinx.directives.HList`` +* ``sphinx.directives.Highlight`` +* ``sphinx.directives.Include`` +* ``sphinx.directives.Index`` +* ``sphinx.directives.LiteralInclude`` +* ``sphinx.directives.Meta`` +* ``sphinx.directives.Only`` +* ``sphinx.directives.SeeAlso`` +* ``sphinx.directives.TabularColumns`` +* ``sphinx.directives.TocTree`` +* ``sphinx.directives.VersionChange`` * ``sphinx.environment.NoUri`` * ``sphinx.ext.autodoc.importer.MockFinder`` * ``sphinx.ext.autodoc.importer.MockLoader`` @@ -28,7 +46,9 @@ For more details, see :ref:`deprecation APIs list <dev-deprecated-apis>`. Features added -------------- +* Add a helper class ``sphinx.transforms.post_transforms.SphinxPostTransform`` * Add a helper method ``SphinxDirective.set_source_info()`` +* #6180: Support ``--keep-going`` with BuildDoc setup command Bugs fixed ---------- diff --git a/doc/conf.py b/doc/conf.py index f29180f77..16594f038 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -48,7 +48,7 @@ epub_fix_images = False epub_max_image_width = 0 epub_show_urls = 'inline' epub_use_index = False -epub_guide = (('toc', 'contents.xhtml', u'Table of Contents'),) +epub_guide = (('toc', 'contents.xhtml', 'Table of Contents'),) epub_description = 'Sphinx documentation generator system manual' latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation', diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst index e57140420..b30537073 100644 --- a/doc/extdev/deprecated.rst +++ b/doc/extdev/deprecated.rst @@ -26,6 +26,96 @@ The following is a list of deprecated interfaces. - (will be) Removed - Alternatives + * - ``sphinx.builders.latex.LaTeXBuilder.apply_transforms()`` + - 2.1 + - 4.0 + - N/A + + * - ``sphinx.directives.Acks`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.Acks`` + + * - ``sphinx.directives.Author`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.Author`` + + * - ``sphinx.directives.Centered`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.Centered`` + + * - ``sphinx.directives.Class`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.Class`` + + * - ``sphinx.directives.CodeBlock`` + - 2.1 + - 4.0 + - ``sphinx.directives.code.CodeBlock`` + + * - ``sphinx.directives.Figure`` + - 2.1 + - 4.0 + - ``sphinx.directives.patches.Figure`` + + * - ``sphinx.directives.HList`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.HList`` + + * - ``sphinx.directives.Highlight`` + - 2.1 + - 4.0 + - ``sphinx.directives.code.Highlight`` + + * - ``sphinx.directives.Include`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.Include`` + + * - ``sphinx.directives.Index`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.Index`` + + * - ``sphinx.directives.LiteralInclude`` + - 2.1 + - 4.0 + - ``sphinx.directives.code.LiteralInclude`` + + * - ``sphinx.directives.Meta`` + - 2.1 + - 4.0 + - ``sphinx.directives.patches.Meta`` + + * - ``sphinx.directives.Only`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.Only`` + + * - ``sphinx.directives.SeeAlso`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.SeeAlso`` + + * - ``sphinx.directives.TabularColumns`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.TabularColumns`` + + * - ``sphinx.directives.TocTree`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.TocTree`` + + * - ``sphinx.directives.VersionChange`` + - 2.1 + - 4.0 + - ``sphinx.directives.other.VersionChange`` + * - ``sphinx.environment.NoUri`` - 2.1 - 4.0 diff --git a/doc/extdev/utils.rst b/doc/extdev/utils.rst index 3aac51ed9..2a94a34bb 100644 --- a/doc/extdev/utils.rst +++ b/doc/extdev/utils.rst @@ -15,6 +15,9 @@ components (e.g. :class:`.Config`, :class:`.BuildEnvironment` and so on) easily. .. autoclass:: sphinx.transforms.SphinxTransform :members: +.. autoclass:: sphinx.transforms.post_transforms.SphinxPostTransform + :members: + .. autoclass:: sphinx.util.docutils.SphinxDirective :members: diff --git a/sphinx/application.py b/sphinx/application.py index 887eae86c..dcd143712 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -91,11 +91,16 @@ builtin_extensions = ( 'sphinx.parsers', 'sphinx.registry', 'sphinx.roles', + 'sphinx.transforms', + 'sphinx.transforms.compact_bullet_list', + 'sphinx.transforms.i18n', + 'sphinx.transforms.references', 'sphinx.transforms.post_transforms', 'sphinx.transforms.post_transforms.code', 'sphinx.transforms.post_transforms.images', 'sphinx.transforms.post_transforms.compat', 'sphinx.util.compat', + 'sphinx.versioning', # collectors should be loaded by specific order 'sphinx.environment.collectors.dependencies', 'sphinx.environment.collectors.asset', diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index f6bfe1b64..3b169e493 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -148,8 +148,8 @@ class ChangesBuilder(Builder): 'text': text } f.write(self.templates.render('changes/rstsource.html', ctx)) - themectx = dict(('theme_' + key, val) for (key, val) in - self.theme.get_options({}).items()) + themectx = {'theme_' + key: val for (key, val) in + self.theme.get_options({}).items()} copy_asset_file(path.join(package_dir, 'themes', 'default', 'static', 'default.css_t'), self.outdir, context=themectx, renderer=self.templates) copy_asset_file(path.join(package_dir, 'themes', 'basic', 'static', 'basic.css'), diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 2c5ebcd4d..3f167d0d3 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -187,7 +187,7 @@ class BuildInfo: self.tags_hash = '' if config: - values = dict((c.name, c.value) for c in config.filter(config_categories)) + values = {c.name: c.value for c in config.filter(config_categories)} self.config_hash = get_stable_hash(values) if tags: diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index c2218fd15..e6467601d 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -9,6 +9,7 @@ """ import os +import warnings from os import path from docutils.frontend import OptionParser @@ -16,17 +17,12 @@ from docutils.frontend import OptionParser import sphinx.builders.latex.nodes # NOQA # Workaround: import this before writer to avoid ImportError from sphinx import package_dir, addnodes, highlighting from sphinx.builders import Builder -from sphinx.builders.latex.transforms import ( - BibliographyTransform, CitationReferenceTransform, MathReferenceTransform, - FootnoteDocnameUpdater, LaTeXFootnoteTransform, LiteralBlockTransform, - ShowUrlsTransform, DocumentTargetTransform, IndexInSectionTitleTransform, -) from sphinx.builders.latex.util import ExtBabel from sphinx.config import ENUM +from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.environment.adapters.asset import ImageAdapter from sphinx.errors import NoUri, SphinxError from sphinx.locale import _, __ -from sphinx.transforms import SphinxTransformer from sphinx.util import texescape, logging, progress_message, status_iterator from sphinx.util.console import bold, darkgreen # type: ignore from sphinx.util.docutils import SphinxFileOutput, new_document @@ -264,7 +260,6 @@ class LaTeXBuilder(Builder): docname, toctree_only, appendices=((docclass != 'howto') and self.config.latex_appendices or [])) doctree['tocdepth'] = tocdepth - self.apply_transforms(doctree) self.post_process_images(doctree) self.update_doc_context(title, author) @@ -340,15 +335,8 @@ class LaTeXBuilder(Builder): def apply_transforms(self, doctree): # type: (nodes.document) -> None - transformer = SphinxTransformer(doctree) - transformer.set_environment(self.env) - transformer.add_transforms([BibliographyTransform, - ShowUrlsTransform, - LaTeXFootnoteTransform, - LiteralBlockTransform, - DocumentTargetTransform, - IndexInSectionTitleTransform]) - transformer.apply_transforms() + warnings.warn('LaTeXBuilder.apply_transforms() is deprecated.', + RemovedInSphinx40Warning) def finish(self): # type: () -> None @@ -485,11 +473,10 @@ def default_latex_documents(config): def setup(app): # type: (Sphinx) -> Dict[str, Any] + app.setup_extension('sphinx.builders.latex.transforms') + app.add_builder(LaTeXBuilder) - app.add_post_transform(CitationReferenceTransform) - app.add_post_transform(MathReferenceTransform) app.connect('config-inited', validate_config_values) - app.add_transform(FootnoteDocnameUpdater) app.add_config_value('latex_engine', default_latex_engine, None, ENUM('pdflatex', 'xelatex', 'lualatex', 'platex')) diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py index 52d5bc9ea..746446fbc 100644 --- a/sphinx/builders/latex/transforms.py +++ b/sphinx/builders/latex/transforms.py @@ -17,11 +17,13 @@ from sphinx.builders.latex.nodes import ( captioned_literal_block, footnotemark, footnotetext, math_reference, thebibliography ) from sphinx.transforms import SphinxTransform +from sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.util.nodes import NodeMatcher if False: # For type annotation - from typing import Any, List, Set, Tuple # NOQA + from typing import Any, Dict, List, Set, Tuple # NOQA + from sphinx.application import Sphinx # NOQA URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:') @@ -38,7 +40,7 @@ class FootnoteDocnameUpdater(SphinxTransform): node['docname'] = self.env.docname -class ShowUrlsTransform(SphinxTransform): +class ShowUrlsTransform(SphinxPostTransform): """Expand references to inline text or footnotes. For more information, see :confval:`latex_show_urls`. @@ -46,11 +48,12 @@ class ShowUrlsTransform(SphinxTransform): .. note:: This transform is used for integrated doctree """ default_priority = 400 + builders = ('latex',) # references are expanded to footnotes (or not) expanded = False - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None try: # replace id_prefix temporarily @@ -177,7 +180,7 @@ class FootnoteCollector(nodes.NodeVisitor): self.footnote_refs.append(node) -class LaTeXFootnoteTransform(SphinxTransform): +class LaTeXFootnoteTransform(SphinxPostTransform): """Convert footnote definitions and references to appropriate form to LaTeX. * Replace footnotes on restricted zone (e.g. headings) by footnotemark node. @@ -345,8 +348,9 @@ class LaTeXFootnoteTransform(SphinxTransform): """ default_priority = 600 + builders = ('latex',) - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None footnotes = list(self.document.traverse(nodes.footnote)) for node in footnotes: @@ -486,7 +490,7 @@ class LaTeXFootnoteVisitor(nodes.NodeVisitor): return None -class BibliographyTransform(SphinxTransform): +class BibliographyTransform(SphinxPostTransform): """Gather bibliography entries to tail of document. Before:: @@ -517,8 +521,9 @@ class BibliographyTransform(SphinxTransform): ... """ default_priority = 750 + builders = ('latex',) - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None citations = thebibliography() for node in self.document.traverse(nodes.citation): @@ -529,19 +534,17 @@ class BibliographyTransform(SphinxTransform): self.document += citations -class CitationReferenceTransform(SphinxTransform): +class CitationReferenceTransform(SphinxPostTransform): """Replace pending_xref nodes for citation by citation_reference. To handle citation reference easily on LaTeX writer, this converts pending_xref nodes to citation_reference. """ default_priority = 5 # before ReferencesResolver + builders = ('latex',) - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None - if self.app.builder.name != 'latex': - return - matcher = NodeMatcher(addnodes.pending_xref, refdomain='std', reftype='citation') citations = self.env.get_domain('std').data['citations'] for node in self.document.traverse(matcher): # type: addnodes.pending_xref @@ -552,19 +555,17 @@ class CitationReferenceTransform(SphinxTransform): node.replace_self(citation_ref) -class MathReferenceTransform(SphinxTransform): +class MathReferenceTransform(SphinxPostTransform): """Replace pending_xref nodes for math by math_reference. To handle math reference easily on LaTeX writer, this converts pending_xref nodes to math_reference. """ default_priority = 5 # before ReferencesResolver + builders = ('latex',) - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None - if self.app.builder.name != 'latex': - return - equations = self.env.get_domain('math').data['objects'] for node in self.document.traverse(addnodes.pending_xref): if node['refdomain'] == 'math' and node['reftype'] in ('eq', 'numref'): @@ -574,30 +575,26 @@ class MathReferenceTransform(SphinxTransform): node.replace_self(refnode) -class LiteralBlockTransform(SphinxTransform): +class LiteralBlockTransform(SphinxPostTransform): """Replace container nodes for literal_block by captioned_literal_block.""" default_priority = 400 + builders = ('latex',) - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None - if self.app.builder.name != 'latex': - return - matcher = NodeMatcher(nodes.container, literal_block=True) for node in self.document.traverse(matcher): # type: nodes.container newnode = captioned_literal_block('', *node.children, **node.attributes) node.replace_self(newnode) -class DocumentTargetTransform(SphinxTransform): +class DocumentTargetTransform(SphinxPostTransform): """Add :doc label to the first section of each document.""" default_priority = 400 + builders = ('latex',) - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None - if self.app.builder.name != 'latex': - return - for node in self.document.traverse(addnodes.start_of_file): section = node.next_node(nodes.section) if section: @@ -639,3 +636,22 @@ class IndexInSectionTitleTransform(SphinxTransform): # move the index node next to the section title node.remove(index) node.parent.insert(i + 1, index) + + +def setup(app): + # type: (Sphinx) -> Dict[str, Any] + app.add_transform(FootnoteDocnameUpdater) + app.add_post_transform(BibliographyTransform) + app.add_post_transform(CitationReferenceTransform) + app.add_post_transform(DocumentTargetTransform) + app.add_post_transform(IndexInSectionTitleTransform) + app.add_post_transform(LaTeXFootnoteTransform) + app.add_post_transform(LiteralBlockTransform) + app.add_post_transform(MathReferenceTransform) + app.add_post_transform(ShowUrlsTransform) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/cmd/build.py b/sphinx/cmd/build.py index 6fd954296..e19500901 100644 --- a/sphinx/cmd/build.py +++ b/sphinx/cmd/build.py @@ -186,7 +186,7 @@ files can be built by specifying individual filenames. group.add_argument('-W', action='store_true', dest='warningiserror', help=__('turn warnings into errors')) group.add_argument('--keep-going', action='store_true', dest='keep_going', - help=__("With -W, Keep going when getting warnings")) + help=__("With -W, keep going when getting warnings")) group.add_argument('-T', action='store_true', dest='traceback', help=__('show full traceback on exception')) group.add_argument('-P', action='store_true', dest='pdb', diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index c8b1b4fdd..dfc096de5 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -349,8 +349,7 @@ document is a custom template, you can also set this to another filename.''')) d['extensions'].append('sphinx.ext.%s' % name) # Handle conflicting options - if set(['sphinx.ext.imgmath', 'sphinx.ext.mathjax']).issubset( - d['extensions']): + if {'sphinx.ext.imgmath', 'sphinx.ext.mathjax'}.issubset(d['extensions']): print(__('Note: imgmath and mathjax cannot be enabled at the same ' 'time. imgmath has been deselected.')) d['extensions'].remove('sphinx.ext.imgmath') @@ -469,7 +468,7 @@ def valid_dir(d): if not path.isdir(dir): return False - if set(['Makefile', 'make.bat']) & set(os.listdir(dir)): + if {'Makefile', 'make.bat'} & set(os.listdir(dir)): return False if d['sep']: @@ -590,7 +589,7 @@ def main(argv=sys.argv[1:]): d = vars(args) # delete None or False value - d = dict((k, v) for k, v in d.items() if v is not None) + d = {k: v for k, v in d.items() if v is not None} # handle use of CSV-style extension values d.setdefault('extensions', []) @@ -601,12 +600,12 @@ def main(argv=sys.argv[1:]): try: if 'quiet' in d: - if not set(['project', 'author']).issubset(d): + if not {'project', 'author'}.issubset(d): print(__('''"quiet" is specified, but any of "project" or \ "author" is not specified.''')) return 1 - if set(['quiet', 'project', 'author']).issubset(d): + if {'quiet', 'project', 'author'}.issubset(d): # quiet mode with all required params satisfied, use default d.setdefault('version', '') d.setdefault('release', d['version']) diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index e10ec8b32..6cdd22ec1 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -37,7 +37,7 @@ def deprecated_alias(modname, objects, warning): sys.modules[modname] = _ModuleWrapper(module, modname, objects, warning) # type: ignore -class _ModuleWrapper(object): +class _ModuleWrapper: def __init__(self, module, modname, objects, warning): # type: (Any, str, Dict, Type[Warning]) -> None self._module = module diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index 1f4520541..e21eb7f6e 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -15,6 +15,7 @@ from docutils import nodes from docutils.parsers.rst import directives, roles from sphinx import addnodes +from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.util import docutils from sphinx.util.docfields import DocFieldTransformer from sphinx.util.docutils import SphinxDirective @@ -186,10 +187,6 @@ class ObjectDescription(SphinxDirective): return [self.indexnode, node] -# backwards compatible old name -DescDirective = ObjectDescription - - class DefaultRole(SphinxDirective): """ Set the default interpreted text role. Overridden from docutils. @@ -242,7 +239,6 @@ class DefaultDomain(SphinxDirective): self.env.temp_data['default_domain'] = self.env.domains.get(domain_name) return [] -# import all directives sphinx provides (for compatibility) from sphinx.directives.code import ( # noqa Highlight, CodeBlock, LiteralInclude ) @@ -254,6 +250,32 @@ from sphinx.directives.patches import ( # noqa Figure, Meta ) +deprecated_alias('sphinx.directives', + { + 'Highlight': Highlight, + 'CodeBlock': CodeBlock, + 'LiteralInclude': LiteralInclude, + 'TocTree': TocTree, + 'Author': Author, + 'Index': Index, + 'VersionChange': VersionChange, + 'SeeAlso': SeeAlso, + 'TabularColumns': TabularColumns, + 'Centered': Centered, + 'Acks': Acks, + 'HList': HList, + 'Only': Only, + 'Include': Include, + 'Class': Class, + 'Figure': Figure, + 'Meta': Meta, + }, + RemovedInSphinx40Warning) + + +# backwards compatible old name (will be marked deprecated in 3.0) +DescDirective = ObjectDescription + def setup(app): # type: (Sphinx) -> Dict[str, Any] diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 46d92f5e1..ec311cfc7 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -72,12 +72,12 @@ class CObject(ObjectDescription): # These C types aren't described anywhere, so don't try to create # a cross-reference to them - stopwords = set(( + stopwords = { 'const', 'void', 'char', 'wchar_t', 'int', 'short', 'long', 'float', 'double', 'unsigned', 'signed', 'FILE', 'clock_t', 'time_t', 'ptrdiff_t', 'size_t', 'ssize_t', 'struct', '_Bool', - )) + } def _parse_type(self, node, ctype): # type: (nodes.Element, str) -> None diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 94f07d91f..2d9a771d1 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -45,7 +45,7 @@ else: ] INITPY = '__init__.py' -PY_SUFFIXES = set(['.py', '.pyx']) +PY_SUFFIXES = {'.py', '.pyx'} def makename(package, module): diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 334a7f8c4..5d96affa4 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -82,7 +82,7 @@ def members_set_option(arg): """Used to convert the :members: option to auto directives.""" if arg is None: return ALL - return set(x.strip() for x in arg.split(',')) + return {x.strip() for x in arg.split(',')} SUPPRESS = object() diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py index b4204ef76..6ae389258 100644 --- a/sphinx/ext/autodoc/mock.py +++ b/sphinx/ext/autodoc/mock.py @@ -40,7 +40,7 @@ class _MockObject: return _make_subclass(args[0], superclass.__display_name__, superclass=superclass, attributes=args[2]) - return super(_MockObject, cls).__new__(cls) + return super().__new__(cls) def __init__(self, *args, **kwargs): # type: (Any, Any) -> None diff --git a/sphinx/ext/ifconfig.py b/sphinx/ext/ifconfig.py index 04653ebc4..bad5953d3 100644 --- a/sphinx/ext/ifconfig.py +++ b/sphinx/ext/ifconfig.py @@ -55,7 +55,7 @@ class IfConfig(SphinxDirective): def process_ifconfig_nodes(app, doctree, docname): # type: (Sphinx, nodes.document, str) -> None - ns = dict((confval.name, confval.value) for confval in app.config) + ns = {confval.name: confval.value for confval in app.config} ns.update(app.config.__dict__.copy()) ns['builder'] = app.builder.name for node in doctree.traverse(ifconfig): diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 9c26d8c56..6b9bc3825 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -150,9 +150,9 @@ def _get_safe_url(url): else: frags = list(parts) if parts.port: - frags[1] = '{0}@{1}:{2}'.format(parts.username, parts.hostname, parts.port) + frags[1] = '{}@{}:{}'.format(parts.username, parts.hostname, parts.port) else: - frags[1] = '{0}@{1}'.format(parts.username, parts.hostname) + frags[1] = '{}@{}'.format(parts.username, parts.hostname) return urlunsplit(frags) diff --git a/sphinx/io.py b/sphinx/io.py index 00fc2bf1a..b5b57d065 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -20,17 +20,12 @@ from docutils.writers import UnfilteredWriter from sphinx.deprecation import RemovedInSphinx30Warning from sphinx.transforms import ( - ApplySourceWorkaround, ExtraTranslatableNodes, SmartQuotesSkipper, CitationReferences, - DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds, FigureAligner, - AutoNumbering, AutoIndexUpgrader, FilterSystemMessages, - UnreferencedFootnotesDetector, SphinxSmartQuotes, DoctreeReadEvent, ManpageLink + AutoIndexUpgrader, DoctreeReadEvent, FigureAligner, SphinxTransformer ) -from sphinx.transforms import SphinxTransformer -from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform from sphinx.transforms.i18n import ( PreserveTranslatableMessages, Locale, RemoveTranslatableInline, ) -from sphinx.transforms.references import SphinxDomains, SubstitutionDefinitionsRemover +from sphinx.transforms.references import SphinxDomains from sphinx.util import logging from sphinx.util import UnicodeDecodeErrorHandler from sphinx.util.docutils import LoggingReporter @@ -93,13 +88,6 @@ class SphinxStandaloneReader(SphinxBaseReader): """ A basic document reader for Sphinx. """ - transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages, - Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, - HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, FigureAligner, - RemoveTranslatableInline, FilterSystemMessages, RefOnlyBulletListTransform, - UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink, - SphinxDomains, SubstitutionDefinitionsRemover, DoctreeReadEvent, - UIDTransform, SmartQuotesSkipper] def __init__(self, app, *args, **kwargs): # type: (Sphinx, Any, Any) -> None @@ -136,12 +124,17 @@ class SphinxI18nReader(SphinxBaseReader): Because the translated texts are partial and they don't have correct line numbers. """ - transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, - DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, - AutoNumbering, SortIds, RemoveTranslatableInline, - FilterSystemMessages, RefOnlyBulletListTransform, - UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink, - SubstitutionDefinitionsRemover, SmartQuotesSkipper] + def __init__(self, app, *args, **kwargs): + # type: (Sphinx, Any, Any) -> None + self.transforms = self.transforms + app.registry.get_transforms() + unused = [PreserveTranslatableMessages, Locale, RemoveTranslatableInline, + AutoIndexUpgrader, FigureAligner, SphinxDomains, DoctreeReadEvent, + UIDTransform] + for transform in unused: + if transform in self.transforms: + self.transforms.remove(transform) + + super().__init__(app, *args, **kwargs) def set_lineno_for_reporter(self, lineno): # type: (int) -> None @@ -202,7 +195,7 @@ class SphinxFileInput(FileInput): def __init__(self, *args, **kwargs): # type: (Any, Any) -> None kwargs['error_handler'] = 'sphinx' - super(SphinxFileInput, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class SphinxRSTFileInput(SphinxBaseFileInput): diff --git a/sphinx/project.py b/sphinx/project.py index c7094503f..8e2e7330a 100644 --- a/sphinx/project.py +++ b/sphinx/project.py @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) EXCLUDE_PATHS = ['**/_sources', '.#*', '**/.#*', '*.lproj/**'] -class Project(object): +class Project: """A project is source code set of Sphinx document.""" def __init__(self, srcdir, source_suffix): diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index dd30b5045..868b0e489 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -310,9 +310,9 @@ class IndexBuilder: rv = {} for k, v in mapping.items(): if isinstance(v, int): - rv[k] = set([index2fn[v]]) + rv[k] = {index2fn[v]} else: - rv[k] = set(index2fn[i] for i in v) + rv[k] = {index2fn[i] for i in v} return rv self._mapping = load_terms(frozen['terms']) @@ -381,12 +381,11 @@ class IndexBuilder: """Create a usable data structure for serializing.""" docnames, titles = zip(*sorted(self._titles.items())) filenames = [self._filenames.get(docname) for docname in docnames] - fn2index = dict((f, i) for (i, f) in enumerate(docnames)) + fn2index = {f: i for (i, f) in enumerate(docnames)} terms, title_terms = self.get_terms(fn2index) objects = self.get_objects(fn2index) # populates _objtypes - objtypes = dict((v, k[0] + ':' + k[1]) - for (k, v) in self._objtypes.items()) + objtypes = {v: k[0] + ':' + k[1] for (k, v) in self._objtypes.items()} objnames = self._objnames return dict(docnames=docnames, filenames=filenames, titles=titles, terms=terms, objects=objects, objtypes=objtypes, objnames=objnames, diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py index 814296f79..0c11af74d 100644 --- a/sphinx/search/ja.py +++ b/sphinx/search/ja.py @@ -155,14 +155,14 @@ class JanomeSplitter(BaseSplitter): class DefaultSplitter(BaseSplitter): - patterns_ = dict([(re.compile(pattern), value) for pattern, value in { + patterns_ = {re.compile(pattern): value for pattern, value in { '[一二三四五六七八九十百千万億兆]': 'M', '[一-龠々〆ヵヶ]': 'H', '[ぁ-ん]': 'I', '[ァ-ヴーア-ン゙ー]': 'K', '[a-zA-Za-zA-Z]': 'A', '[0-90-9]': 'N', - }.items()]) + }.items()} BIAS__ = -332 BC1__ = {'HH': 6, 'II': 2461, 'KH': 406, 'OH': -1378} BC2__ = {'AA': -3267, 'AI': 2744, 'AN': -878, 'HH': -4070, 'HM': -1711, diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py index 9445e4e0a..06a7016d1 100644 --- a/sphinx/setup_command.py +++ b/sphinx/setup_command.py @@ -85,6 +85,7 @@ class BuildDoc(Command): ('copyright', None, 'The copyright string'), ('pdb', None, 'Start pdb on exception'), ('nitpicky', 'n', 'nit-picky mode, warn about all missing references'), + ('keep-going', None, 'With -W, keep going when getting warnings'), ] boolean_options = ['fresh-env', 'all-files', 'warning-is-error', 'link-index', 'nitpicky'] @@ -106,6 +107,7 @@ class BuildDoc(Command): self.verbosity = 0 self.traceback = False self.nitpicky = False + self.keep_going = False def _guess_source_dir(self): # type: () -> str @@ -186,7 +188,8 @@ class BuildDoc(Command): builder_target_dir, self.doctree_dir, builder, confoverrides, status_stream, freshenv=self.fresh_env, - warningiserror=self.warning_is_error) + warningiserror=self.warning_is_error, + keep_going=self.keep_going) app.build(force_all=self.all_files) if app.statuscode: raise DistutilsExecError( diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py index fbd05c5d1..7b73059e9 100644 --- a/sphinx/testing/util.py +++ b/sphinx/testing/util.py @@ -133,8 +133,8 @@ class SphinxTestApp(application.Sphinx): self._saved_directives = directives._directives.copy() # type: ignore self._saved_roles = roles._roles.copy() # type: ignore - self._saved_nodeclasses = set(v for v in dir(nodes.GenericNodeVisitor) - if v.startswith('visit_')) + self._saved_nodeclasses = {v for v in dir(nodes.GenericNodeVisitor) + if v.startswith('visit_')} try: super().__init__(srcdir, confdir, outdir, doctreedir, diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index dd7a4c04f..2fc1b6e72 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -29,7 +29,7 @@ from sphinx.util.nodes import ( if False: # For type annotation - from typing import Any, Generator, List, Tuple # NOQA + from typing import Any, Dict, Generator, List, Tuple # NOQA from sphinx.application import Sphinx # NOQA from sphinx.config import Config # NOQA from sphinx.domain.std import StandardDomain # NOQA @@ -38,11 +38,11 @@ if False: logger = logging.getLogger(__name__) -default_substitutions = set([ +default_substitutions = { 'version', 'release', 'today', -]) +} class SphinxTransform(Transform): @@ -438,3 +438,29 @@ class ManpageLink(SphinxTransform): if r: info = r.groupdict() node.attributes.update(info) + + +def setup(app): + # type: (Sphinx) -> Dict[str, Any] + app.add_transform(ApplySourceWorkaround) + app.add_transform(ExtraTranslatableNodes) + app.add_transform(SmartQuotesSkipper) + app.add_transform(CitationReferences) + app.add_transform(DefaultSubstitutions) + app.add_transform(MoveModuleTargets) + app.add_transform(HandleCodeBlocks) + app.add_transform(SortIds) + app.add_transform(FigureAligner) + app.add_transform(AutoNumbering) + app.add_transform(AutoIndexUpgrader) + app.add_transform(FilterSystemMessages) + app.add_transform(UnreferencedFootnotesDetector) + app.add_transform(SphinxSmartQuotes) + app.add_transform(DoctreeReadEvent) + app.add_transform(ManpageLink) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py index 7f7db5c40..e118e6a84 100644 --- a/sphinx/transforms/compact_bullet_list.py +++ b/sphinx/transforms/compact_bullet_list.py @@ -17,7 +17,8 @@ from sphinx.transforms import SphinxTransform if False: # For type annotation - from typing import Any, List # NOQA + from typing import Any, Dict, List # NOQA + from sphinx.application import Sphinx # NOQA class RefOnlyListChecker(nodes.GenericNodeVisitor): @@ -90,3 +91,14 @@ class RefOnlyBulletListTransform(SphinxTransform): compact_para = addnodes.compact_paragraph() compact_para += ref item.replace(para, compact_para) + + +def setup(app): + # type: (Sphinx) -> Dict[str, Any] + app.add_transform(RefOnlyBulletListTransform) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index c8628c318..c884bb89d 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -483,3 +483,16 @@ class RemoveTranslatableInline(SphinxTransform): for inline in self.document.traverse(matcher): # type: nodes.inline inline.parent.remove(inline) inline.parent += inline.children + + +def setup(app): + # type: (Sphinx) -> Dict[str, Any] + app.add_transform(PreserveTranslatableMessages) + app.add_transform(Locale) + app.add_transform(RemoveTranslatableInline) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index be144b793..8f64266d0 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -29,14 +29,48 @@ if False: logger = logging.getLogger(__name__) -class ReferencesResolver(SphinxTransform): +class SphinxPostTransform(SphinxTransform): + """A base class of post-transforms. + + Post transforms are invoked to modify the document to restructure it for outputting. + They do resolving references, convert images, special transformation for each output + formats and so on. This class helps to implement these post transforms. + """ + builders = () # type: Tuple[str, ...] + formats = () # type: Tuple[str, ...] + + def apply(self, **kwargs): + # type: (Any) -> None + if self.is_supported(): + self.run(**kwargs) + + def is_supported(self): + # type: () -> bool + """Check this transform working for current builder.""" + if self.builders and self.app.builder.name not in self.builders: + return False + if self.formats and self.app.builder.format not in self.formats: + return False + + return True + + def run(self, **kwargs): + # type: (Any) -> None + """main method of post transforms. + + Subclasses should override this method instead of ``apply()``. + """ + raise NotImplementedError + + +class ReferencesResolver(SphinxPostTransform): """ Resolves cross-references on doctrees. """ default_priority = 10 - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None for node in self.document.traverse(addnodes.pending_xref): contnode = cast(nodes.TextElement, node[0].deepcopy()) @@ -147,10 +181,10 @@ class ReferencesResolver(SphinxTransform): location=node, type='ref', subtype=typ) -class OnlyNodeTransform(SphinxTransform): +class OnlyNodeTransform(SphinxPostTransform): default_priority = 50 - def apply(self, **kwargs): + def run(self, **kwargs): # type: (Any) -> None # A comment on the comment() nodes being inserted: replacing by [] would # result in a "Losing ids" exception if there is a target node before diff --git a/sphinx/transforms/references.py b/sphinx/transforms/references.py index fd7e71779..de512f437 100644 --- a/sphinx/transforms/references.py +++ b/sphinx/transforms/references.py @@ -15,7 +15,8 @@ from sphinx.transforms import SphinxTransform if False: # For type annotation - from typing import Any # NOQA + from typing import Any, Dict # NOQA + from sphinx.application import Sphinx # NOQA class SubstitutionDefinitionsRemover(SphinxTransform): @@ -38,3 +39,15 @@ class SphinxDomains(SphinxTransform): # type: (Any) -> None for domain in self.env.domains.values(): domain.process_doc(self.env, self.env.docname, self.document) + + +def setup(app): + # type: (Sphinx) -> Dict[str, Any] + app.add_transform(SubstitutionDefinitionsRemover) + app.add_transform(SphinxDomains) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index fc3f76ef3..2ebae8768 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -138,7 +138,7 @@ class FilenameUniqDict(dict): while uniquename in self._existing: i += 1 uniquename = '%s%s%s' % (base, i, ext) - self[newfile] = (set([docname]), uniquename) + self[newfile] = ({docname}, uniquename) self._existing.add(uniquename) return uniquename diff --git a/sphinx/versioning.py b/sphinx/versioning.py index d69720c57..c98d166bc 100644 --- a/sphinx/versioning.py +++ b/sphinx/versioning.py @@ -20,8 +20,9 @@ from sphinx.transforms import SphinxTransform if False: # For type annotation - from typing import Any, Iterator # NOQA + from typing import Any, Dict, Iterator # NOQA from docutils import nodes # NOQA + from sphinx.application import Sphinx # NOQA try: import Levenshtein @@ -186,3 +187,14 @@ def prepare(document): RemovedInSphinx30Warning, stacklevel=2) transform = UIDTransform(document) transform.apply() + + +def setup(app): + # type: (Sphinx) -> Dict[str, Any] + app.add_transform(UIDTransform) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/tests/test_application.py b/tests/test_application.py index 08c13c5cf..f10592b51 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -64,7 +64,7 @@ def test_extension_in_blacklist(app, status, warning): @pytest.mark.filterwarnings('ignore:The config variable "source_parsers"') @pytest.mark.filterwarnings('ignore:app.add_source_parser\\(\\) does not support suffix') def test_add_source_parser(app, status, warning): - assert set(app.config.source_suffix) == set(['.rst', '.md', '.test']) + assert set(app.config.source_suffix) == {'.rst', '.md', '.test'} # .rst; only in :confval:`source_suffix` assert '.rst' not in app.registry.get_source_parsers() diff --git a/tests/test_builder.py b/tests/test_builder.py index 35197a8ef..fa64f0c1f 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -28,7 +28,7 @@ def test_incremental_reading(app): # second reading updated = app.builder.read() - assert set(updated) == set(['index', 'new']) + assert set(updated) == {'index', 'new'} assert 'autodoc' not in app.env.all_docs assert 'autodoc' not in app.env.found_docs @@ -44,4 +44,4 @@ def test_incremental_reading_for_missing_files(app): # "index" is listed up to updated because it contains references # to nonexisting downloadable or image files - assert set(updated) == set(['index']) + assert set(updated) == {'index'} diff --git a/tests/test_catalogs.py b/tests/test_catalogs.py index f5fffa9d6..1a14d46e6 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -43,10 +43,10 @@ def test_compile_all_catalogs(app, status, warning): locale_dir = app.srcdir / 'locale' catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES' - expect = set([ + expect = { x.replace('.po', '.mo') for x in find_files(catalog_dir, '.po') - ]) + } actual = set(find_files(catalog_dir, '.mo')) assert actual # not empty assert actual == expect @@ -67,7 +67,7 @@ def test_compile_specific_catalogs(app, status, warning): actual_on_boot = get_actual() # sphinx.mo might be included app.builder.compile_specific_catalogs([app.srcdir / 'admonitions.txt']) actual = get_actual() - actual_on_boot - assert actual == set(['admonitions.mo']) + assert actual == {'admonitions.mo'} @pytest.mark.usefixtures('setup_test') @@ -80,10 +80,10 @@ def test_compile_update_catalogs(app, status, warning): locale_dir = app.srcdir / 'locale' catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES' - expect = set([ + expect = { x.replace('.po', '.mo') for x in find_files(catalog_dir, '.po') - ]) + } actual = set(find_files(catalog_dir, '.mo')) assert actual # not empty assert actual == expect diff --git a/tests/test_environment.py b/tests/test_environment.py index df0aa20b0..15562536f 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -25,21 +25,20 @@ def test_images(app): htmlbuilder.imgpath = 'dummy' htmlbuilder.post_process_images(tree) assert set(htmlbuilder.images.keys()) == \ - set(['subdir/img.png', 'img.png', 'subdir/simg.png', 'svgimg.svg', - 'img.foo.png']) + {'subdir/img.png', 'img.png', 'subdir/simg.png', 'svgimg.svg', 'img.foo.png'} assert set(htmlbuilder.images.values()) == \ - set(['img.png', 'img1.png', 'simg.png', 'svgimg.svg', 'img.foo.png']) + {'img.png', 'img1.png', 'simg.png', 'svgimg.svg', 'img.foo.png'} latexbuilder = LaTeXBuilder(app) latexbuilder.set_environment(app.env) latexbuilder.init() latexbuilder.post_process_images(tree) assert set(latexbuilder.images.keys()) == \ - set(['subdir/img.png', 'subdir/simg.png', 'img.png', 'img.pdf', - 'svgimg.pdf', 'img.foo.png']) + {'subdir/img.png', 'subdir/simg.png', 'img.png', 'img.pdf', + 'svgimg.pdf', 'img.foo.png'} assert set(latexbuilder.images.values()) == \ - set(['img.pdf', 'img.png', 'img1.png', 'simg.png', - 'svgimg.pdf', 'img.foo.png']) + {'img.pdf', 'img.png', 'img1.png', 'simg.png', + 'svgimg.pdf', 'img.foo.png'} @pytest.mark.sphinx('dummy') diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py index c490dcedf..9d880d92c 100644 --- a/tests/test_environment_toctree.py +++ b/tests/test_environment_toctree.py @@ -75,11 +75,11 @@ def test_process_doc(app): # other collections assert app.env.toc_num_entries['index'] == 6 assert app.env.toctree_includes['index'] == ['foo', 'bar', 'baz'] - assert app.env.files_to_rebuild['foo'] == set(['index']) - assert app.env.files_to_rebuild['bar'] == set(['index']) - assert app.env.files_to_rebuild['baz'] == set(['index']) + assert app.env.files_to_rebuild['foo'] == {'index'} + assert app.env.files_to_rebuild['bar'] == {'index'} + assert app.env.files_to_rebuild['baz'] == {'index'} assert app.env.glob_toctrees == set() - assert app.env.numbered_toctrees == set(['index']) + assert app.env.numbered_toctrees == {'index'} # qux has no section title assert len(app.env.tocs['qux']) == 0 diff --git a/tests/test_ext_coverage.py b/tests/test_ext_coverage.py index d02d65feb..73181909d 100644 --- a/tests/test_ext_coverage.py +++ b/tests/test_ext_coverage.py @@ -37,7 +37,7 @@ def test_build(app, status, warning): undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').bytes()) assert len(undoc_c) == 1 # the key is the full path to the header file, which isn't testable - assert list(undoc_c.values())[0] == set([('function', 'Py_SphinxTest')]) + assert list(undoc_c.values())[0] == {('function', 'Py_SphinxTest')} assert 'autodoc_target' in undoc_py assert 'funcs' in undoc_py['autodoc_target'] diff --git a/tests/test_ext_inheritance_diagram.py b/tests/test_ext_inheritance_diagram.py index 9e5d3e60f..03b5bb689 100644 --- a/tests/test_ext_inheritance_diagram.py +++ b/tests/test_ext_inheritance_diagram.py @@ -121,7 +121,7 @@ def test_import_classes(rootdir): # all of classes in the module classes = import_classes('sphinx.application', None) - assert set(classes) == set([Sphinx, TemplateBridge]) + assert set(classes) == {Sphinx, TemplateBridge} # specified class in the module classes = import_classes('sphinx.application.Sphinx', None) diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index fa75062b3..86ded7d89 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -36,7 +36,7 @@ class NamedtupleSubclass(namedtuple('NamedtupleSubclass', ('attr1', 'attr2'))): __slots__ = () def __new__(cls, attr1, attr2=None): - return super(NamedtupleSubclass, cls).__new__(cls, attr1, attr2) + return super().__new__(cls, attr1, attr2) class BaseDocstringTest(TestCase): diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 2ce7ac95e..3fca33f6f 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -54,9 +54,9 @@ def test_todo(app, status, warning): # check handled event assert len(todos) == 3 - assert set(todo[1].astext() for todo in todos) == {'todo in foo', - 'todo in bar', - 'todo in param field'} + assert {todo[1].astext() for todo in todos} == {'todo in foo', + 'todo in bar', + 'todo in param field'} @pytest.mark.sphinx('html', testroot='ext-todo', freshenv=True, @@ -92,9 +92,9 @@ def test_todo_not_included(app, status, warning): # check handled event assert len(todos) == 3 - assert set(todo[1].astext() for todo in todos) == {'todo in foo', - 'todo in bar', - 'todo in param field'} + assert {todo[1].astext() for todo in todos} == {'todo in foo', + 'todo in bar', + 'todo in param field'} @pytest.mark.sphinx('latex', testroot='ext-todo', freshenv=True, diff --git a/tests/test_intl.py b/tests/test_intl.py index 002851f07..ddb22ef9f 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -818,8 +818,7 @@ def test_xml_footnote_backlinks(app): para0 = secs[0].findall('paragraph') refs0 = para0[0].findall('footnote_reference') - refid2id = dict([ - (r.attrib.get('refid'), r.attrib.get('ids')) for r in refs0]) + refid2id = {r.attrib.get('refid'): r.attrib.get('ids') for r in refs0} footnote0 = secs[0].findall('footnote') for footnote in footnote0: diff --git a/tests/test_util_i18n.py b/tests/test_util_i18n.py index 5208689e8..4737d465c 100644 --- a/tests/test_util_i18n.py +++ b/tests/test_util_i18n.py @@ -70,13 +70,13 @@ def test_get_catalogs_for_xx(tempdir): (tempdir / 'loc1' / 'xx' / 'LC_ALL' / 'test7.po').write_text('#') catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', force_all=False) - domains = set(c.domain for c in catalogs) - assert domains == set([ + domains = {c.domain for c in catalogs} + assert domains == { 'test1', 'test2', 'sub/test4', 'sub/test5', - ]) + } def test_get_catalogs_for_en(tempdir): @@ -86,8 +86,8 @@ def test_get_catalogs_for_en(tempdir): (tempdir / 'loc1' / 'en' / 'LC_MESSAGES' / 'en_dom.po').write_text('#') catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'en', force_all=False) - domains = set(c.domain for c in catalogs) - assert domains == set(['en_dom']) + domains = {c.domain for c in catalogs} + assert domains == {'en_dom'} def test_get_catalogs_with_non_existent_locale(tempdir): @@ -121,13 +121,13 @@ def test_get_catalogs_for_xx_without_outdated(tempdir): assert not catalogs catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', force_all=True) - domains = set(c.domain for c in catalogs) - assert domains == set([ + domains = {c.domain for c in catalogs} + assert domains == { 'test1', 'test2', 'sub/test4', 'sub/test5', - ]) + } def test_get_catalogs_from_multiple_locale_dirs(tempdir): @@ -152,8 +152,8 @@ def test_get_catalogs_with_compact(tempdir): (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#') catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', gettext_compact=True) - domains = set(c.domain for c in catalogs) - assert domains == set(['test1', 'test2', 'sub/test3', 'sub/test4']) + domains = {c.domain for c in catalogs} + assert domains == {'test1', 'test2', 'sub/test3', 'sub/test4'} def test_get_catalogs_excluded(tempdir): @@ -163,8 +163,8 @@ def test_get_catalogs_excluded(tempdir): catalogs = i18n.find_catalog_source_files( [tempdir / 'loc1'], 'en', force_all=False, excluded=lambda path: '.git' in path) - domains = set(c.domain for c in catalogs) - assert domains == set(['en_dom']) + domains = {c.domain for c in catalogs} + assert domains == {'en_dom'} def test_format_date(): diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index 6cb2a4b1b..ba2bb7501 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -352,7 +352,7 @@ def test_set_sorting(): def test_set_sorting_fallback(): - set_ = set((None, 1)) + set_ = {None, 1} description = inspect.object_description(set_) assert description in ("{1, None}", "{None, 1}") diff --git a/utils/jssplitter_generator.py b/utils/jssplitter_generator.py index 255bc0a98..360ce7d15 100644 --- a/utils/jssplitter_generator.py +++ b/utils/jssplitter_generator.py @@ -79,7 +79,7 @@ function splitQuery(query) { } ''' % (fold(singles, ','), fold(ranges, '],')) -js_test_src = u''' +js_test_src = ''' // This is regression test for https://github.com/sphinx-doc/sphinx/issues/3150 // generated by compat_regexp_generator.py // it needs node.js for testing |