From bee5f45a682f36b7182cdf71c33f08f3bb40d1f9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 14 Mar 2019 02:07:05 +0900 Subject: [PATCH 1/5] Fix #6172: AttributeError is raised for old styled index nodes --- CHANGES | 1 + sphinx/util/compat.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index b48ee5e75..d15580368 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,7 @@ Bugs fixed classes attribute refers missing citation (refs: #6147) * #2155: Support ``code`` directive * C++, fix parsing of braced initializers. +* #6172: AttributeError is raised for old styled index nodes Testing -------- diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py index 1567bad9e..5d8cbb3db 100644 --- a/sphinx/util/compat.py +++ b/sphinx/util/compat.py @@ -58,12 +58,12 @@ class IndexEntriesMigrator(SphinxTransform): def apply(self, **kwargs): # type: (Any) -> None for node in self.document.traverse(addnodes.index): - for entries in node['entries']: + for i, entries in enumerate(node['entries']): if len(entries) == 4: source, line = get_source_line(node) warnings.warn('An old styled index node found: %r at (%s:%s)' % (node, source, line), RemovedInSphinx40Warning) - entries.extend([None]) + node['entries'][i] = entries + (None,) def setup(app): From 22afc77c488e85ccd51303a223f450705b30217b Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Sun, 17 Mar 2019 12:49:36 -0700 Subject: [PATCH 2/5] Python-3-only clean ups discovered by pyupgrade https://github.com/asottile/pyupgrade > A tool to automatically upgrade syntax for newer versions of the > language. - Drop u str prefix - Drop base object inheritance - Drop args to super() - Use set literals - Use dict comprehension - Use set comprehension --- doc/conf.py | 2 +- sphinx/builders/changes.py | 4 ++-- sphinx/builders/html.py | 2 +- sphinx/cmd/quickstart.py | 11 +++++------ sphinx/deprecation.py | 2 +- sphinx/domains/c.py | 4 ++-- sphinx/ext/apidoc.py | 2 +- sphinx/ext/autodoc/__init__.py | 2 +- sphinx/ext/ifconfig.py | 2 +- sphinx/ext/intersphinx.py | 4 ++-- sphinx/io.py | 2 +- sphinx/project.py | 2 +- sphinx/search/__init__.py | 9 ++++----- sphinx/search/ja.py | 4 ++-- sphinx/testing/util.py | 4 ++-- sphinx/transforms/__init__.py | 4 ++-- sphinx/util/__init__.py | 2 +- tests/test_application.py | 2 +- tests/test_builder.py | 4 ++-- tests/test_catalogs.py | 10 +++++----- tests/test_environment.py | 13 ++++++------- tests/test_environment_toctree.py | 8 ++++---- tests/test_ext_coverage.py | 2 +- tests/test_ext_inheritance_diagram.py | 2 +- tests/test_ext_napoleon_docstring.py | 2 +- tests/test_ext_todo.py | 12 ++++++------ tests/test_intl.py | 3 +-- tests/test_util_i18n.py | 24 ++++++++++++------------ tests/test_util_inspect.py | 2 +- utils/jssplitter_generator.py | 2 +- 30 files changed, 72 insertions(+), 76 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 58cbfe708..d32ee47ae 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/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/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/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 f4b0c368f..5c94d611d 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -80,7 +80,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/ifconfig.py b/sphinx/ext/ifconfig.py index 4fd5fa391..930ed9954 100644 --- a/sphinx/ext/ifconfig.py +++ b/sphinx/ext/ifconfig.py @@ -56,7 +56,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 368f661d5..d3c4b2183 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -202,7 +202,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/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 6f513377b..d489db334 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -36,11 +36,11 @@ if False: logger = logging.getLogger(__name__) -default_substitutions = set([ +default_substitutions = { 'version', 'release', 'today', -]) +} class SphinxTransform(Transform): diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index def90125c..b266b955d 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/tests/test_application.py b/tests/test_application.py index 87ee72f63..6bc454311 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -61,7 +61,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 14fca84d5..1355280e3 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -42,10 +42,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 @@ -66,7 +66,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') @@ -79,10 +79,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 367409fd9..35e8f6909 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -829,8 +829,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 b25e29575..a0d0d5577 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 From 4e27cc465a0ff71ff06e302aad1f7e2196fe3f39 Mon Sep 17 00:00:00 2001 From: Michael Goerz Date: Sun, 10 Mar 2019 18:37:05 -0400 Subject: [PATCH 3/5] Fix docs of inheritance-diagram "parts" option The documentation now correctly describes the behavior of the ``parts`` option in an inheritance-diagram directive: it gives the number of parts that are *kept* not dropped. The option now also accepts negative values, which drops parts from the left (which is the what the documentation incorrectly claimed the option would do for positive values) As a form of testing of the new functionality, the documentation for the inheritance_diagram extension now includes a section "Examples" that demonstrate the different possibilities. This would fail to build without the patch. Closes #4872 --- CHANGES | 1 + doc/conf.py | 2 +- doc/usage/extensions/inheritance.rst | 51 +++++++++++++++++++++++++--- sphinx/ext/inheritance_diagram.py | 16 ++++++--- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index d15580368..5c361e207 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,7 @@ Bugs fixed * #2155: Support ``code`` directive * C++, fix parsing of braced initializers. * #6172: AttributeError is raised for old styled index nodes +* #4872: ext.inheritance_diagram: correctly describe behavior of ``parts`` option in docs, allow negative values. Testing -------- diff --git a/doc/conf.py b/doc/conf.py index d32ee47ae..16594f038 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -7,7 +7,7 @@ import sphinx extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks', - 'sphinx.ext.viewcode'] + 'sphinx.ext.viewcode', 'sphinx.ext.inheritance_diagram'] master_doc = 'contents' templates_path = ['_templates'] diff --git a/doc/usage/extensions/inheritance.rst b/doc/usage/extensions/inheritance.rst index c66f4130f..8e98b0bc1 100644 --- a/doc/usage/extensions/inheritance.rst +++ b/doc/usage/extensions/inheritance.rst @@ -25,12 +25,18 @@ It adds this directive: graph. This directive supports an option called ``parts`` that, if given, must be an - integer, advising the directive to remove that many parts of module names - from the displayed names. (For example, if all your class names start with - ``lib.``, you can give ``:parts: 1`` to remove that prefix from the displayed - node names.) + integer, advising the directive to keep that many dot-separated parts + in the displayed names (from right to left). For example, ``parts=1`` will + only display class names, without the names of the modules that contain + them. - It also supports a ``private-bases`` flag option; if given, private base + .. versionchanged:: 2.0 + The value of for ``parts`` can also be negative, indicating how many + parts to drop from the left. For example, if all your class names start + with ``lib.``, you can give ``:parts: -1`` to remove that prefix from the + displayed node names. + + The directive also supports a ``private-bases`` flag option; if given, private base classes (those whose name starts with ``_``) will be included. You can use ``caption`` option to give a caption to the diagram. @@ -92,6 +98,41 @@ It adds this directive: Added ``top-classes`` option to limit the scope of inheritance graphs. +Examples +-------- + +The following are different inheritance diagrams for the internal +``InheritanceDiagram`` class that implements the directive. + +With full names:: + + .. inheritance-diagram:: sphinx.ext.inheritance_diagram.InheritanceDiagram + +.. inheritance-diagram:: sphinx.ext.inheritance_diagram.InheritanceDiagram + + +Showing class names only:: + + .. inheritance-diagram:: sphinx.ext.inheritance_diagram.InheritanceDiagram + :parts: 1 + +.. inheritance-diagram:: sphinx.ext.inheritance_diagram.InheritanceDiagram + :parts: 1 + +Stopping the diagram at :class:`sphinx.util.docutils.SphinxDirective` (the +highest superclass still part of Sphinx), and dropping the common left-most +part (``sphinx``) from all names:: + + .. inheritance-diagram:: sphinx.ext.inheritance_diagram.InheritanceDiagram + :top-classes: sphinx.util.docutils.SphinxDirective + :parts: -1 + +.. inheritance-diagram:: sphinx.ext.inheritance_diagram.InheritanceDiagram + :top-classes: sphinx.util.docutils.SphinxDirective + :parts: -1 + + + Configuration ------------- diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index cfdac4803..df3ff01ed 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -167,11 +167,17 @@ class InheritanceGraph: """Return name and bases for all classes that are ancestors of *classes*. - *parts* gives the number of dotted name parts that is removed from the - displayed node names. + *parts* gives the number of dotted name parts to include in the + displayed node names, from right to left. If given as a negative, the + number of parts to drop from the left. A value of 0 displays the full + dotted name. E.g. ``sphinx.ext.inheritance_diagram.InheritanceGraph`` + with ``parts=2`` or ``parts=-2`` gets displayed as + ``inheritance_diagram.InheritanceGraph``, and as + ``ext.inheritance_diagram.InheritanceGraph`` with ``parts=3`` or + ``parts=-1``. - *top_classes* gives the name(s) of the top most ancestor class to traverse - to. Multiple names can be specified separated by comma. + *top_classes* gives the name(s) of the top most ancestor class to + traverse to. Multiple names can be specified separated by comma. """ all_classes = {} py_builtins = vars(builtins).values() @@ -332,7 +338,7 @@ class InheritanceDiagram(SphinxDirective): optional_arguments = 0 final_argument_whitespace = True option_spec = { - 'parts': directives.nonnegative_int, + 'parts': int, 'private-bases': directives.flag, 'caption': directives.unchanged, 'top-classes': directives.unchanged_required, From ac6de0a2d9d1b7a81a0dbbc61decca7b54ec91a9 Mon Sep 17 00:00:00 2001 From: Michael Goerz Date: Mon, 11 Mar 2019 14:35:50 -0400 Subject: [PATCH 4/5] Install graphiz on Travis This is required to generate inheritance diagrams (as there is now an example inheritance diagram in the documentation of the extension generating such diagrams) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5a49bf106..7bc822d70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,7 @@ matrix: services: xvfb install: + - "sudo apt-get install graphviz" - if [ $IS_PYTHON = true ]; then pip install -U tox codecov; fi - if [ $IS_PYTHON = false ]; then npm install; fi From 79da4c777dcb032650c74f35253eb2bf7c95732b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 19 Mar 2019 01:19:59 +0900 Subject: [PATCH 5/5] Update CHANGES --- CHANGES | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 5c361e207..0c6f70d10 100644 --- a/CHANGES +++ b/CHANGES @@ -33,7 +33,8 @@ Bugs fixed * #2155: Support ``code`` directive * C++, fix parsing of braced initializers. * #6172: AttributeError is raised for old styled index nodes -* #4872: ext.inheritance_diagram: correctly describe behavior of ``parts`` option in docs, allow negative values. +* #4872: inheritance_diagram: correctly describe behavior of ``parts`` option in + docs, allow negative values. Testing --------