From 0bc8e006a6cbea7e2fc9497d68b0a55833aafacb Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Tue, 26 Jul 2022 15:59:37 -0400 Subject: [PATCH 1/6] MAINT: Bump version to dev (#982) --- sphinx_gallery/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_gallery/__init__.py b/sphinx_gallery/__init__.py index f62249831..de20e5992 100644 --- a/sphinx_gallery/__init__.py +++ b/sphinx_gallery/__init__.py @@ -6,7 +6,7 @@ import os # dev versions should have "dev" in them, stable should not. # doc/conf.py makes use of this to set the version drop-down. -__version__ = '0.11.0' +__version__ = '0.12.0.dev0' def glr_path_static(): From 4072df489b3e52647a244362715dc9bbdda54a6d Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 6 Aug 2022 14:03:38 -0400 Subject: [PATCH 2/6] Remove old sphinx compatibility code (#985) This code was for Sphinx < 1.6, and the minimum is now 1.8.3, so this should have been dropped in #513. --- sphinx_gallery/backreferences.py | 4 +- sphinx_gallery/binder.py | 7 +- sphinx_gallery/docs_resolv.py | 7 +- sphinx_gallery/gen_gallery.py | 7 +- sphinx_gallery/gen_rst.py | 6 +- sphinx_gallery/notebook.py | 4 +- sphinx_gallery/py_source_parser.py | 2 +- sphinx_gallery/sphinx_compatibility.py | 71 ----------------- sphinx_gallery/tests/conftest.py | 10 +-- .../tests/test_sphinx_compatibility.py | 77 ------------------- sphinx_gallery/utils.py | 5 +- 11 files changed, 23 insertions(+), 177 deletions(-) delete mode 100644 sphinx_gallery/sphinx_compatibility.py delete mode 100644 sphinx_gallery/tests/test_sphinx_compatibility.py diff --git a/sphinx_gallery/backreferences.py b/sphinx_gallery/backreferences.py index bbff2b0e4..eecbab61b 100644 --- a/sphinx_gallery/backreferences.py +++ b/sphinx_gallery/backreferences.py @@ -19,8 +19,8 @@ import warnings from sphinx.errors import ExtensionError +import sphinx.util -from . import sphinx_compatibility from .scrapers import _find_image_ext from .utils import _replace_md5 from .directives import THUMBNAIL_PARENT_DIV, THUMBNAIL_PARENT_DIV_CLOSE @@ -322,7 +322,7 @@ def _write_backreferences(backrefs, seen_backrefs, gallery_conf, def _finalize_backreferences(seen_backrefs, gallery_conf): """Replace backref files only if necessary.""" - logger = sphinx_compatibility.getLogger('sphinx-gallery') + logger = sphinx.util.logging.getLogger('sphinx-gallery') if gallery_conf['backreferences_dir'] is None: return diff --git a/sphinx_gallery/binder.py b/sphinx_gallery/binder.py index 64f7fd569..8230b76f8 100644 --- a/sphinx_gallery/binder.py +++ b/sphinx_gallery/binder.py @@ -20,12 +20,13 @@ from urllib.parse import quote from sphinx.errors import ConfigError +import sphinx.util from .utils import replace_py_ipynb -from . import sphinx_compatibility, glr_path_static +from . import glr_path_static -logger = sphinx_compatibility.getLogger('sphinx-gallery') +logger = sphinx.util.logging.getLogger('sphinx-gallery') def gen_binder_url(fpath, binder_conf, gallery_conf): @@ -204,7 +205,7 @@ def _copy_binder_notebooks(app): if not isinstance(gallery_dirs, (list, tuple)): gallery_dirs = [gallery_dirs] - iterator = sphinx_compatibility.status_iterator( + iterator = sphinx.util.status_iterator( gallery_dirs, 'copying binder notebooks...', length=len(gallery_dirs)) for i_folder in iterator: diff --git a/sphinx_gallery/docs_resolv.py b/sphinx_gallery/docs_resolv.py index e56f45327..cd182b161 100644 --- a/sphinx_gallery/docs_resolv.py +++ b/sphinx_gallery/docs_resolv.py @@ -21,11 +21,10 @@ from sphinx.errors import ExtensionError from sphinx.search import js_index +import sphinx.util -from . import sphinx_compatibility - -logger = sphinx_compatibility.getLogger('sphinx-gallery') +logger = sphinx.util.logging.getLogger('sphinx-gallery') def _get_data(url): @@ -345,7 +344,7 @@ def _embed_code_links(app, gallery_conf, gallery_dir): flat = [[dirpath, filename] for dirpath, _, filenames in os.walk(html_gallery_dir) for filename in filenames] - iterator = sphinx_compatibility.status_iterator( + iterator = sphinx.util.status_iterator( flat, 'embedding documentation hyperlinks for %s... ' % gallery_dir, color='fuchsia', length=len(flat), stringify_func=lambda x: os.path.basename(x[1])) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 2da42e509..cfb5763d4 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -22,8 +22,9 @@ from xml.sax.saxutils import quoteattr, escape from sphinx.errors import ConfigError, ExtensionError +import sphinx.util from sphinx.util.console import red -from . import sphinx_compatibility, glr_path_static, __version__ as _sg_version +from . import glr_path_static, __version__ as _sg_version from .utils import _replace_md5, _has_optipng, _has_pypandoc from .backreferences import _finalize_backreferences from .gen_rst import (generate_dir_rst, SPHX_GLR_SIG, _get_memory_base, @@ -103,7 +104,7 @@ def __call__(self, gallery_conf, script_vars): 'prefer_full_module': [], } -logger = sphinx_compatibility.getLogger('sphinx-gallery') +logger = sphinx.util.logging.getLogger('sphinx-gallery') def _bool_eval(x): @@ -903,8 +904,6 @@ def default_getter(conf): def setup(app): """Setup Sphinx-Gallery sphinx extension""" - sphinx_compatibility._app = app - app.add_config_value('sphinx_gallery_conf', DEFAULT_GALLERY_CONF, 'html') for key in ['plot_gallery', 'abort_on_example_error']: app.add_config_value(key, get_default_config_value(key), 'html') diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index d78c0280a..d2458d7a0 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -34,13 +34,13 @@ import codeop from sphinx.errors import ExtensionError +import sphinx.util from .scrapers import (save_figures, ImagePathIterator, clean_modules, _find_image_ext) from .utils import (replace_py_ipynb, scale_image, get_md5sum, _replace_md5, optipng) from . import glr_path_static -from . import sphinx_compatibility from .backreferences import (_write_backreferences, _thumbnail_div, identify_names) from .downloads import CODE_DOWNLOAD @@ -51,7 +51,7 @@ from .notebook import jupyter_notebook, save_notebook from .binder import check_binder_conf, gen_binder_rst -logger = sphinx_compatibility.getLogger('sphinx-gallery') +logger = sphinx.util.logging.getLogger('sphinx-gallery') ############################################################################### @@ -437,7 +437,7 @@ def generate_dir_rst( costs = [] subsection_toctree_filenames = [] build_target_dir = os.path.relpath(target_dir, gallery_conf['src_dir']) - iterator = sphinx_compatibility.status_iterator( + iterator = sphinx.util.status_iterator( sorted_listdir, 'generating gallery for %s... ' % build_target_dir, length=len(sorted_listdir)) diff --git a/sphinx_gallery/notebook.py b/sphinx_gallery/notebook.py index b00ad9312..3f8165834 100644 --- a/sphinx_gallery/notebook.py +++ b/sphinx_gallery/notebook.py @@ -24,12 +24,12 @@ import textwrap from sphinx.errors import ExtensionError +import sphinx.util -from . import sphinx_compatibility from .py_source_parser import split_code_and_text_blocks from .utils import replace_py_ipynb -logger = sphinx_compatibility.getLogger('sphinx-gallery') +logger = sphinx.util.logging.getLogger('sphinx-gallery') def jupyter_notebook_skeleton(): diff --git a/sphinx_gallery/py_source_parser.py b/sphinx_gallery/py_source_parser.py index f19230325..fcccbc108 100644 --- a/sphinx_gallery/py_source_parser.py +++ b/sphinx_gallery/py_source_parser.py @@ -16,7 +16,7 @@ from textwrap import dedent from sphinx.errors import ExtensionError -from .sphinx_compatibility import getLogger +from sphinx.util.logging import getLogger logger = getLogger('sphinx-gallery') diff --git a/sphinx_gallery/sphinx_compatibility.py b/sphinx_gallery/sphinx_compatibility.py deleted file mode 100644 index 4dfdca60a..000000000 --- a/sphinx_gallery/sphinx_compatibility.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Backwards-compatility shims for Sphinx -====================================== - -""" -from __future__ import division, absolute_import, print_function - -import sphinx -import sphinx.util - - -# This gets set when the extension is initialized. -_app = None - - -def _app_get_logger(name): - class SphinxLoggerAdapter: - def _color_to_func(self, kwargs, default=''): - return getattr(sphinx.util.console, - kwargs.pop('color', default), - None) - - def error(self, msg, *args, **kwargs): - msg = msg % args - colorfunc = self._color_to_func(kwargs, default='red') - return _app.warn(colorfunc(msg), **kwargs) - - def critical(self, msg, *args, **kwargs): - msg = msg % args - colorfunc = self._color_to_func(kwargs, default='red') - return _app.warn(colorfunc(msg), **kwargs) - - def warning(self, msg, *args, **kwargs): - msg = msg % args - colorfunc = self._color_to_func(kwargs) - if colorfunc: - # colorfunc is a valid kwarg in 1.5, but not older, so we just - # apply it ourselves. - msg = colorfunc(msg) - return _app.warn(msg, **kwargs) - - def info(self, msg='', *args, **kwargs): - msg = msg % args - colorfunc = self._color_to_func(kwargs) - if colorfunc: - msg = colorfunc(msg) - return _app.info(msg, **kwargs) - - def verbose(self, msg, *args, **kwargs): - return _app.verbose(msg, *args, **kwargs) - - def debug(self, msg, *args, **kwargs): - return _app.debug(msg, *args, **kwargs) - - return SphinxLoggerAdapter() - - -def _app_status_iterator(iterable, summary, **kwargs): - global _app - - color = kwargs.pop('color', None) - if color is not None: - kwargs['colorfunc'] = getattr(sphinx.util.console, color) - - for item in _app.status_iterator(iterable, summary, **kwargs): - yield item - - -getLogger = sphinx.util.logging.getLogger -status_iterator = sphinx.util.status_iterator diff --git a/sphinx_gallery/tests/conftest.py b/sphinx_gallery/tests/conftest.py index 980656cb0..67a293498 100644 --- a/sphinx_gallery/tests/conftest.py +++ b/sphinx_gallery/tests/conftest.py @@ -17,7 +17,7 @@ from sphinx.errors import ExtensionError from sphinx.util.docutils import docutils_namespace from sphinx_gallery import (docs_resolv, gen_gallery, gen_rst, utils, - sphinx_compatibility, py_source_parser) + py_source_parser) from sphinx_gallery.scrapers import _import_matplotlib from sphinx_gallery.utils import _get_image @@ -69,12 +69,7 @@ def gallery_conf(tmpdir): @pytest.fixture def fakesphinxapp(): - orig_app = sphinx_compatibility._app - sphinx_compatibility._app = app = FakeSphinxApp() - try: - yield app - finally: - sphinx_compatibility._app = orig_app + yield FakeSphinxApp() @pytest.fixture @@ -198,7 +193,6 @@ def create_sphinx_app_context(self): with docutils_namespace(): app = Sphinx(self.srcdir, self.confdir, self.outdir, self.doctreedir, self.buildername, **self.kwargs) - sphinx_compatibility._app = app yield app def build_sphinx_app(self, *args, **kwargs): diff --git a/sphinx_gallery/tests/test_sphinx_compatibility.py b/sphinx_gallery/tests/test_sphinx_compatibility.py deleted file mode 100644 index 9dba26c6e..000000000 --- a/sphinx_gallery/tests/test_sphinx_compatibility.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Testing the Sphinx compatibility shims -""" -from __future__ import division, absolute_import, print_function - -import sphinx.util.console - -from sphinx_gallery import sphinx_compatibility - - -def test_status_iterator(fakesphinxapp): - for _ in sphinx_compatibility._app_status_iterator([1, 2, 3], - 'summary', - length=3): - pass - - assert len(fakesphinxapp.calls['status_iterator']) == 1 - call = fakesphinxapp.calls['status_iterator'][0] - assert call.args == ([1, 2, 3], 'summary') - assert 'color' not in call.kwargs - assert 'colorfunc' not in call.kwargs - assert call.kwargs['length'] == 3 - - -def test_status_iterator_color(fakesphinxapp): - for _ in sphinx_compatibility._app_status_iterator([1, 2, 3], - 'summary', - color='green', - length=3): - pass - - assert len(fakesphinxapp.calls['status_iterator']) == 1 - call = fakesphinxapp.calls['status_iterator'][0] - assert call.args == ([1, 2, 3], 'summary') - assert 'color' not in call.kwargs - assert call.kwargs['colorfunc'] == sphinx.util.console.green - assert call.kwargs['length'] == 3 - - -def test_get_logger(fakesphinxapp): - logger = sphinx_compatibility._app_get_logger('sphinx-gallery-tests') - logger.error('error') - logger.critical('critical') - logger.warning('warning 1') - logger.warning('warning 2', color='green') - logger.info('info 1') - logger.info('info 2', color='green') - logger.verbose('verbose') - logger.debug('debug') - - # Error + critical both go through warning: - assert len(fakesphinxapp.calls['warn']) == 4 - error, critical, warning1, warning2 = fakesphinxapp.calls['warn'] - assert error.args == (sphinx.util.console.red('error'), ) - assert error.kwargs == {} - assert critical.args == (sphinx.util.console.red('critical'), ) - assert critical.kwargs == {} - assert warning1.args == ('warning 1', ) - assert warning1.kwargs == {} - assert warning2.args == (sphinx.util.console.green('warning 2'), ) - assert warning2.kwargs == {} - - assert len(fakesphinxapp.calls['info']) == 2 - info1, info2 = fakesphinxapp.calls['info'] - assert info1.args == ('info 1', ) - assert info1.kwargs == {} - assert info2.args == (sphinx.util.console.green('info 2'), ) - assert info2.kwargs == {} - - assert len(fakesphinxapp.calls['verbose']) == 1 - assert fakesphinxapp.calls['verbose'][0].args == ('verbose', ) - assert fakesphinxapp.calls['verbose'][0].kwargs == {} - - assert len(fakesphinxapp.calls['debug']) == 1 - assert fakesphinxapp.calls['debug'][0].args == ('debug', ) - assert fakesphinxapp.calls['debug'][0].kwargs == {} diff --git a/sphinx_gallery/utils.py b/sphinx_gallery/utils.py index f0db5f355..23276e5f8 100644 --- a/sphinx_gallery/utils.py +++ b/sphinx_gallery/utils.py @@ -15,10 +15,11 @@ from shutil import move, copyfile import subprocess -from . import sphinx_compatibility from sphinx.errors import ExtensionError +import sphinx.util -logger = sphinx_compatibility.getLogger('sphinx-gallery') + +logger = sphinx.util.logging.getLogger('sphinx-gallery') def _get_image(): From edf8a01593891fd14666aea774911eeb29732922 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 6 Aug 2022 16:46:56 -0400 Subject: [PATCH 3/6] Use Mock more in tests (#986) * Replace FakeSphinxApp with a Mock No need to re-implement something that's in the standard library. * Use a Mock in gallery_conf fixture This also drops the last use of `Bunch`. --- sphinx_gallery/tests/conftest.py | 44 ++----------------- sphinx_gallery/tests/test_gen_rst.py | 39 ++++++++-------- sphinx_gallery/tests/test_py_source_parser.py | 6 +-- sphinx_gallery/utils.py | 8 ---- 4 files changed, 26 insertions(+), 71 deletions(-) diff --git a/sphinx_gallery/tests/conftest.py b/sphinx_gallery/tests/conftest.py index 67a293498..f2ba6b629 100644 --- a/sphinx_gallery/tests/conftest.py +++ b/sphinx_gallery/tests/conftest.py @@ -4,11 +4,11 @@ """ from __future__ import division, absolute_import, print_function -import collections from contextlib import contextmanager from io import StringIO import os import shutil +from unittest.mock import Mock import pytest @@ -16,8 +16,7 @@ from sphinx.application import Sphinx from sphinx.errors import ExtensionError from sphinx.util.docutils import docutils_namespace -from sphinx_gallery import (docs_resolv, gen_gallery, gen_rst, utils, - py_source_parser) +from sphinx_gallery import docs_resolv, gen_gallery, gen_rst, py_source_parser from sphinx_gallery.scrapers import _import_matplotlib from sphinx_gallery.utils import _get_image @@ -27,54 +26,19 @@ def pytest_report_header(config, startdir): return 'Sphinx: %s (%s)' % (sphinx.__version__, sphinx.__file__) -Params = collections.namedtuple('Params', 'args kwargs') - - -class FakeSphinxApp: - def __init__(self): - self.calls = collections.defaultdict(list) - - def status_iterator(self, *args, **kwargs): - self.calls['status_iterator'].append(Params(args, kwargs)) - for it in args[0]: - yield it - - def warning(self, *args, **kwargs): - self.calls['warning'].append(Params(args, kwargs)) - - def warn(self, *args, **kwargs): - self.calls['warn'].append(Params(args, kwargs)) - - def info(self, *args, **kwargs): - self.calls['info'].append(Params(args, kwargs)) - - def verbose(self, *args, **kwargs): - self.calls['verbose'].append(Params(args, kwargs)) - - def debug(self, *args, **kwargs): - self.calls['debug'].append(Params(args, kwargs)) - - @pytest.fixture def gallery_conf(tmpdir): """Set up a test sphinx-gallery configuration.""" - app = utils.Bunch() - app.add_css_file = lambda x: None - app.config = dict(source_suffix={'.rst': None}) + app = Mock(spec=Sphinx, config=dict(source_suffix={'.rst': None})) gallery_conf = gen_gallery._complete_gallery_conf( {}, str(tmpdir), True, False, app=app) gallery_conf.update(examples_dir=str(tmpdir), gallery_dir=str(tmpdir)) return gallery_conf -@pytest.fixture -def fakesphinxapp(): - yield FakeSphinxApp() - - @pytest.fixture def log_collector(monkeypatch): - app = FakeSphinxApp() + app = Mock(spec=Sphinx, name='FakeSphinxApp')() monkeypatch.setattr(docs_resolv, 'logger', app) monkeypatch.setattr(gen_gallery, 'logger', app) monkeypatch.setattr(py_source_parser, 'logger', app) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 92462d72d..0e6d14bc7 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -360,8 +360,8 @@ def test_fail_example(gallery_conf, failing_code, want, sg.generate_file_rst('raise.py', gallery_conf['gallery_dir'], gallery_conf['examples_dir'], gallery_conf) - assert len(log_collector.calls['warning']) == 1 - msg = log_collector.calls['warning'][0].args[2] + log_collector.warning.assert_called_once() + msg = log_collector.warning.call_args[0][2] assert want in msg assert 'gen_gallery' not in msg # can only check that gen_rst is removed on non-input ones @@ -549,7 +549,7 @@ def test_exclude_implicit(gallery_conf, @pytest.mark.parametrize('ext', ('.txt', '.rst', '.bad')) -def test_gen_dir_rst(gallery_conf, fakesphinxapp, ext): +def test_gen_dir_rst(gallery_conf, ext): """Test gen_dir_rst.""" print(os.listdir(gallery_conf['examples_dir'])) fname_readme = os.path.join(gallery_conf['src_dir'], 'README.txt') @@ -993,9 +993,9 @@ def test_full_line(log_collector_wrap): tee.write('Output\n') tee.flush() assert output_file.getvalue() == 'Output\n' - assert len(log_collector.calls['verbose']) == 2 - assert src_filename in log_collector.calls['verbose'][0].args - assert 'Output' in log_collector.calls['verbose'][1].args + assert log_collector.verbose.call_count == 2 + assert src_filename in log_collector.verbose.call_args_list[0][0] + assert 'Output' in log_collector.verbose.call_args_list[1][0] def test_incomplete_line_with_flush(log_collector_wrap): @@ -1003,13 +1003,13 @@ def test_incomplete_line_with_flush(log_collector_wrap): log_collector, src_filename, tee, output_file = log_collector_wrap tee.write('Output') assert output_file.getvalue() == 'Output' - assert len(log_collector.calls['verbose']) == 1 - assert src_filename in log_collector.calls['verbose'][0].args + log_collector.verbose.assert_called_once() + assert src_filename in log_collector.verbose.call_args[0] # ... should appear when flushed. tee.flush() - assert len(log_collector.calls['verbose']) == 2 - assert 'Output' in log_collector.calls['verbose'][1].args + assert log_collector.verbose.call_count == 2 + assert 'Output' in log_collector.verbose.call_args_list[1][0] def test_incomplete_line_with_more_output(log_collector_wrap): @@ -1017,15 +1017,15 @@ def test_incomplete_line_with_more_output(log_collector_wrap): log_collector, src_filename, tee, output_file = log_collector_wrap tee.write('Output') assert output_file.getvalue() == 'Output' - assert len(log_collector.calls['verbose']) == 1 - assert src_filename in log_collector.calls['verbose'][0].args + log_collector.verbose.assert_called_once() + assert src_filename in log_collector.verbose.call_args[0] # ... should appear when more data is written. tee.write('\nMore output\n') assert output_file.getvalue() == 'Output\nMore output\n' - assert len(log_collector.calls['verbose']) == 3 - assert 'Output' in log_collector.calls['verbose'][1].args - assert 'More output' in log_collector.calls['verbose'][2].args + assert log_collector.verbose.call_count == 3 + assert 'Output' in log_collector.verbose.call_args_list[1][0] + assert 'More output' in log_collector.verbose.call_args_list[2][0] def test_multi_line(log_collector_wrap): @@ -1033,11 +1033,10 @@ def test_multi_line(log_collector_wrap): tee.write('first line\rsecond line\nthird line') assert (output_file.getvalue() == 'first line\rsecond line\nthird line') - verbose_calls = log_collector.calls['verbose'] - assert len(verbose_calls) == 3 - assert src_filename in verbose_calls[0].args - assert 'first line' in verbose_calls[1].args - assert 'second line' in verbose_calls[2].args + assert log_collector.verbose.call_count == 3 + assert src_filename in log_collector.verbose.call_args_list[0][0] + assert 'first line' in log_collector.verbose.call_args_list[1][0] + assert 'second line' in log_collector.verbose.call_args_list[2][0] assert tee.logger_buffer == 'third line' diff --git a/sphinx_gallery/tests/test_py_source_parser.py b/sphinx_gallery/tests/test_py_source_parser.py index 72bc50dd4..7dd87e138 100644 --- a/sphinx_gallery/tests/test_py_source_parser.py +++ b/sphinx_gallery/tests/test_py_source_parser.py @@ -54,11 +54,11 @@ def test_get_docstring_and_rest(unicode_sample, tmpdir, monkeypatch): def test_extract_file_config(content, file_conf, log_collector): if file_conf is None: assert sg.extract_file_config(content) == {} - assert len(log_collector.calls['warning']) == 1 - assert '1foo' == log_collector.calls['warning'][0].args[2] + log_collector.warning.assert_called_once() + assert '1foo' == log_collector.warning.call_args[0][2] else: assert sg.extract_file_config(content) == file_conf - assert len(log_collector.calls['warning']) == 0 + log_collector.warning.assert_not_called() @pytest.mark.parametrize('contents, result', [ diff --git a/sphinx_gallery/utils.py b/sphinx_gallery/utils.py index 23276e5f8..574fca1a7 100644 --- a/sphinx_gallery/utils.py +++ b/sphinx_gallery/utils.py @@ -165,14 +165,6 @@ def _replace_md5(fname_new, fname_old=None, method='move', mode='b'): assert os.path.isfile(fname_old) -class Bunch(dict): - """Dictionary-like object that exposes its keys as attributes.""" - - def __init__(self, **kwargs): # noqa: D102 - dict.__init__(self, kwargs) - self.__dict__ = self - - def _has_pypandoc(): """Check if pypandoc package available.""" try: From 18705f8948008df84bf6c6b38df4d88d701d3979 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Wed, 17 Aug 2022 13:44:07 -0400 Subject: [PATCH 4/6] BUG: Fix links (#991) --- doc/projects_list.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/projects_list.rst b/doc/projects_list.rst index 701d8b99f..ed8d30005 100644 --- a/doc/projects_list.rst +++ b/doc/projects_list.rst @@ -4,7 +4,7 @@ Who uses Sphinx-Gallery Here is a list of projects using `sphinx-gallery`. -* :ref:`Sphinx-Gallery ` +* :ref:`Sphinx-Gallery ` * :doc:`Scikit-learn ` * `Nilearn `_ * `MNE-python `_ From f4a283a972eeea593b0a2acd559c0d11cf8eb0e9 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Fri, 19 Aug 2022 11:15:53 -0400 Subject: [PATCH 5/6] BUG: Fix single column example (#993) * TST: Expose bug with divs * BUG: Fix bug with doubling * FIX: Better test * FIX: Bump req to 3 * FIX: Try another * FIX: Restoer * FIX: Better name * FIX: Possible * FIX: re --- CHANGES.rst | 10 ++++++++ azure-pipelines.yml | 4 +-- continuous_integration/azure/install.sh | 2 +- dev-requirements.txt | 2 +- requirements.txt | 2 +- sphinx_gallery/backreferences.py | 17 ++++++++++++- sphinx_gallery/directives.py | 32 +++++------------------ sphinx_gallery/gen_rst.py | 18 ++----------- sphinx_gallery/tests/test_full.py | 34 ++++++++++++++++++++++++- 9 files changed, 73 insertions(+), 48 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 91bd1da6e..305f059aa 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,16 @@ Change Log ========== +v0.12.0 +------- + +Support for Sphinx < 3 dropped in this release. Requirement is Sphinx >= 3. + +**Fixed bugs:** + +- BUG: Fix single column example `#993 `__ (`larsoner `__) + + v0.11.0 ------- diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6e2777aea..2533c0784 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -94,10 +94,10 @@ stages: DISTRIB: 'ubuntu' PYTHON_VERSION: '3.7' SPHINXOPTS: '' - conda_python37_sphinx183: + conda_python37_sphinxOld: DISTRIB: 'conda' PYTHON_VERSION: '3.7' - SPHINX_VERSION: '1.8.3' + SPHINX_VERSION: '3' LOCALE: 'C' conda_python38_sphinxDev: DISTRIB: 'conda' diff --git a/continuous_integration/azure/install.sh b/continuous_integration/azure/install.sh index 23f18ae08..27da4e7f1 100644 --- a/continuous_integration/azure/install.sh +++ b/continuous_integration/azure/install.sh @@ -67,7 +67,7 @@ elif [ "$DISTRIB" == "ubuntu" ]; then python3 -m pip install -r dev-requirements.txt | cat python3 -m pip install --upgrade pytest pytest-cov coverage # test show_memory=True without memory_profiler by not installing it (not in req) - python3 -m pip install sphinx==1.8.3 "jinja2<=3.0.3" + python3 -m pip install sphinx==3 "jinja2<=3.0.3" python3 setup.py install --user python3 -m pip list else diff --git a/dev-requirements.txt b/dev-requirements.txt index ac66ad56a..beba0e285 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,4 +1,4 @@ -sphinx>=1.8.3 +sphinx>=3 sphinx_rtd_theme pytest pytest-coverage diff --git a/requirements.txt b/requirements.txt index 7287bd257..070f3fd35 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -sphinx>=1.8.3 +sphinx>=3 diff --git a/sphinx_gallery/backreferences.py b/sphinx_gallery/backreferences.py index eecbab61b..1eac38866 100644 --- a/sphinx_gallery/backreferences.py +++ b/sphinx_gallery/backreferences.py @@ -23,7 +23,21 @@ from .scrapers import _find_image_ext from .utils import _replace_md5 -from .directives import THUMBNAIL_PARENT_DIV, THUMBNAIL_PARENT_DIV_CLOSE + + +THUMBNAIL_PARENT_DIV = """ +.. raw:: html + +
+ +""" + +THUMBNAIL_PARENT_DIV_CLOSE = """ +.. raw:: html + +
+ +""" class DummyClass(object): @@ -311,6 +325,7 @@ def _write_backreferences(backrefs, seen_backrefs, gallery_conf, heading = 'Examples using ``%s``' % backref ex_file.write('\n\n' + heading + '\n') ex_file.write('^' * len(heading) + '\n') + ex_file.write('\n\n.. start-sphx-glr-thumbnails\n\n') # Open a div which will contain all thumbnails # (it will be closed in _finalize_backreferences) ex_file.write(THUMBNAIL_PARENT_DIV) diff --git a/sphinx_gallery/directives.py b/sphinx_gallery/directives.py index 0e5cdfb71..0029bd61e 100644 --- a/sphinx_gallery/directives.py +++ b/sphinx_gallery/directives.py @@ -14,21 +14,6 @@ from sphinx.errors import ExtensionError -THUMBNAIL_PARENT_DIV = """ -.. raw:: html - -
- -""" - -THUMBNAIL_PARENT_DIV_CLOSE = """ -.. raw:: html - -
- -""" - - class MiniGallery(Directive): """ Custom directive to insert a mini-gallery @@ -87,21 +72,18 @@ def has_backrefs(obj): if not any(has_backrefs(obj) for obj in obj_list): return [] - # Add div containing all thumbnails; - # this is helpful for controlling grid or flexbox behaviours - lines.append(THUMBNAIL_PARENT_DIV) - - # Insert the backreferences file(s) using the `include` directive + # Insert the backreferences file(s) using the `include` directive. + # This already includes the opening
+ # and its closing
. for obj in obj_list: path = os.path.join('/', # Sphinx treats this as the source dir backreferences_dir, '{}.examples'.format(obj)) - # Always remove the heading (first 5 lines) from the file - lines.append('.. include:: {}\n :start-line: 5'.format(path)) - - # Close thumbnail parent div - lines.append(THUMBNAIL_PARENT_DIV_CLOSE) + # Always remove the heading from the file + lines.append("""\ +.. include:: {} + :start-after: start-sphx-glr-thumbnails""".format(path)) # Parse the assembly of `include` and `raw` directives text = '\n'.join(lines) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index d2458d7a0..69dd71495 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -42,7 +42,8 @@ optipng) from . import glr_path_static from .backreferences import (_write_backreferences, _thumbnail_div, - identify_names) + identify_names, THUMBNAIL_PARENT_DIV, + THUMBNAIL_PARENT_DIV_CLOSE) from .downloads import CODE_DOWNLOAD from .py_source_parser import (split_code_and_text_blocks, remove_config_comments, @@ -348,21 +349,6 @@ def _get_readme(dir_, gallery_conf, raise_error=True): return None -THUMBNAIL_PARENT_DIV = """ -.. raw:: html - -
- -""" - -THUMBNAIL_PARENT_DIV_CLOSE = """ -.. raw:: html - -
- -""" - - def generate_dir_rst( src_dir, target_dir, diff --git a/sphinx_gallery/tests/test_full.py b/sphinx_gallery/tests/test_full.py index 008334d0c..a1bbc3504 100644 --- a/sphinx_gallery/tests/test_full.py +++ b/sphinx_gallery/tests/test_full.py @@ -395,7 +395,7 @@ def test_backreferences(sphinx_app): ('sphinx_gallery.sorting.ExplicitOrder.examples', 'plot_second_future_imports'), ]) -def test_backreferences_examples(sphinx_app, rst_file, example_used_in): +def test_backreferences_examples_rst(sphinx_app, rst_file, example_used_in): """Test linking to mini-galleries using backreferences_dir.""" backref_dir = sphinx_app.srcdir examples_rst = op.join(backref_dir, 'gen_modules', 'backreferences', @@ -403,6 +403,38 @@ def test_backreferences_examples(sphinx_app, rst_file, example_used_in): with codecs.open(examples_rst, 'r', 'utf-8') as fid: lines = fid.read() assert example_used_in in lines + # check the .. raw:: html div count + n_open = lines.count('