From 76ad32e94b4df75fa2d0010b36b8ca34df0e4f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 14 Feb 2016 15:30:27 +0100 Subject: [PATCH 01/60] Writing block fails to stderr --- sphinx_gallery/gen_rst.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 9e7111b56..1978091a6 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -96,6 +96,7 @@ def flush(self): class MixedEncodingStringIO(StringIO): """Helper when both ASCII and unicode strings will be written""" + def write(self, data): if not isinstance(data, unicode): data = data.decode('utf-8') @@ -526,11 +527,10 @@ def execute_script(code_block, example_globals, image_path, fig_count, except Exception: formatted_exception = traceback.format_exc() - sys.stdout = orig_stdout # need this here so these lines don't bomb - print(80 * '_') - print('%s is not compiling:' % src_file) - print(formatted_exception) - print(80 * '_') + sys.stderr.write(80 * '_' + '\n') + sys.stderr.write('%s is not compiling:' % src_file) + sys.stderr.write(formatted_exception) + sys.stderr.write(80 * '_' + '\n') figure_list = [] image_list = codestr2rst(formatted_exception, lang='pytb') From 3a56e3c53c2ae0737895ed4865ca053fe90a11e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 14 Feb 2016 17:39:37 +0100 Subject: [PATCH 02/60] Print a list at build end of Failing examples --- sphinx_gallery/docs_resolv.py | 3 +++ sphinx_gallery/gen_gallery.py | 24 +++++++++++++----------- sphinx_gallery/gen_rst.py | 2 ++ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/sphinx_gallery/docs_resolv.py b/sphinx_gallery/docs_resolv.py index 0675a131d..6490877c2 100644 --- a/sphinx_gallery/docs_resolv.py +++ b/sphinx_gallery/docs_resolv.py @@ -434,3 +434,6 @@ def embed_code_links(app, exception): for gallery_dir in gallery_dirs: _embed_code_links(app, gallery_conf, gallery_dir) + + sys.stderr.write("Failed examples:") + sys.stderr.write(str(gallery_conf['failed_examples'])) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 9b742cf98..6134c29f6 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -12,12 +12,22 @@ from __future__ import division, print_function, absolute_import +import copy import re import os from . import glr_path_static from .gen_rst import generate_dir_rst, SPHX_GLR_SIG from .docs_resolv import embed_code_links +DEFAULT_GALLERY_CONF = { + 'filename_pattern': re.escape(os.sep) + 'plot', + 'examples_dirs': '../examples', + 'gallery_dirs': 'auto_examples', + 'mod_example_dir': os.path.join('modules', 'generated'), + 'doc_module': (), + 'reference_url': {}, +} + def clean_gallery_out(build_dir): """Deletes images under the sphx_glr namespace in the build directory""" @@ -55,8 +65,10 @@ def generate_gallery_rst(app): except TypeError: plot_gallery = bool(app.builder.config.plot_gallery) + gallery_conf = copy.deepcopy(DEFAULT_GALLERY_CONF) gallery_conf.update(app.config.sphinx_gallery_conf) gallery_conf.update(plot_gallery=plot_gallery) + gallery_conf.update(failed_examples=[]) gallery_conf.update( abort_on_example_error=app.builder.config.abort_on_example_error) @@ -143,21 +155,11 @@ def touch_empty_backreferences(app, what, name, obj, options, lines): open(examples_path, 'w').close() -gallery_conf = { - 'filename_pattern': re.escape(os.sep) + 'plot', - 'examples_dirs': '../examples', - 'gallery_dirs': 'auto_examples', - 'mod_example_dir': os.path.join('modules', 'generated'), - 'doc_module': (), - 'reference_url': {}, -} - - def setup(app): """Setup sphinx-gallery sphinx extension""" app.add_config_value('plot_gallery', True, 'html') app.add_config_value('abort_on_example_error', False, 'html') - app.add_config_value('sphinx_gallery_conf', gallery_conf, 'html') + app.add_config_value('sphinx_gallery_conf', DEFAULT_GALLERY_CONF, 'html') app.add_stylesheet('gallery.css') if 'sphinx.ext.autodoc' in app._extensions: diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 1978091a6..05dd66f4e 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -545,6 +545,8 @@ def execute_script(code_block, example_globals, image_path, fig_count, # `raise RuntimeError` by the `my_stdout` call, maybe use `.get()`? if gallery_conf['abort_on_example_error']: raise + # Stores failing file + gallery_conf['failed_examples'].append(src_file) finally: os.chdir(cwd) From 7652b6e77be45b1bb20012acaf46dbd817927ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 14 Feb 2016 18:31:13 +0100 Subject: [PATCH 03/60] Exit code on build finish --- sphinx_gallery/docs_resolv.py | 3 --- sphinx_gallery/gen_gallery.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/sphinx_gallery/docs_resolv.py b/sphinx_gallery/docs_resolv.py index 6490877c2..0675a131d 100644 --- a/sphinx_gallery/docs_resolv.py +++ b/sphinx_gallery/docs_resolv.py @@ -434,6 +434,3 @@ def embed_code_links(app, exception): for gallery_dir in gallery_dirs: _embed_code_links(app, gallery_conf, gallery_dir) - - sys.stderr.write("Failed examples:") - sys.stderr.write(str(gallery_conf['failed_examples'])) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 6134c29f6..124b11724 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -15,6 +15,7 @@ import copy import re import os +import sys from . import glr_path_static from .gen_rst import generate_dir_rst, SPHX_GLR_SIG from .docs_resolv import embed_code_links @@ -155,6 +156,16 @@ def touch_empty_backreferences(app, what, name, obj, options, lines): open(examples_path, 'w').close() +def exit_on_fail_examples(app, exception): + """Embed hyperlinks to documentation into example code""" + if exception is not None: + return + gallery_conf = app.config.sphinx_gallery_conf + sys.stderr.write("Failed examples:") + sys.stderr.write(str(gallery_conf['failed_examples'])) + sys.exit(1) + + def setup(app): """Setup sphinx-gallery sphinx extension""" app.add_config_value('plot_gallery', True, 'html') From f56ba727e3abcef4f3ac3d57019af1ebd9adf60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 14 Feb 2016 19:15:32 +0100 Subject: [PATCH 04/60] Failed examples only trigger when examples fail --- sphinx_gallery/gen_gallery.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 124b11724..047d2db1e 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -160,10 +160,12 @@ def exit_on_fail_examples(app, exception): """Embed hyperlinks to documentation into example code""" if exception is not None: return + gallery_conf = app.config.sphinx_gallery_conf - sys.stderr.write("Failed examples:") - sys.stderr.write(str(gallery_conf['failed_examples'])) - sys.exit(1) + if len(gallery_conf['failed_examples']): + sys.stderr.write("Failed examples:\n\n") + sys.stderr.write("\n".join(gallery_conf['failed_examples']) + '\n\n') + sys.exit(1) def setup(app): @@ -178,6 +180,7 @@ def setup(app): app.connect('builder-inited', generate_gallery_rst) + app.connect('build-finished', exit_on_fail_examples) app.connect('build-finished', embed_code_links) From c59d0b52357607ced96393a8743e0839044c51a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 14 Feb 2016 18:35:58 +0100 Subject: [PATCH 05/60] Stop building examples after a fail Fix #88 --- sphinx_gallery/gen_rst.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 05dd66f4e..548c519ca 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -482,6 +482,9 @@ def execute_script(code_block, example_globals, image_path, fig_count, time_elapsed = 0 stdout = '' + if src_file in gallery_conf['failed_examples']: + return '', 0, 0 + # We need to execute the code print('plotting code blocks in %s' % src_file) From aa6598829bb681f1ea3f6b8e8855b5d8a0ea4476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 14 Feb 2016 19:58:59 +0100 Subject: [PATCH 06/60] Setub test build --- sphinx_gallery/gen_gallery.py | 4 ++++ sphinx_gallery/tests/test_gen_rst.py | 30 ++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 047d2db1e..66b909102 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -27,6 +27,10 @@ 'mod_example_dir': os.path.join('modules', 'generated'), 'doc_module': (), 'reference_url': {}, + # build options + 'plot_gallery': True, + 'abort_on_example_error': False, + 'failed_examples': [], } diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 787ed7949..a415b9e86 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -8,6 +8,7 @@ unicode_literals) import ast import codecs +import copy import json import tempfile import re @@ -17,6 +18,7 @@ from nose.tools import assert_equal, assert_false, assert_true import sphinx_gallery.gen_rst as sg +from sphinx_gallery import gen_gallery from sphinx_gallery import notebook import matplotlib.pylab as plt # Import gen_rst first to enable 'Agg' backend. @@ -127,20 +129,21 @@ def test_md5sums(): os.remove(f.name + '.md5') +def build_temp_setup(**kwargs): + """Sets a test build up""" + + gallery_conf = copy.deepcopy(gen_gallery.DEFAULT_GALLERY_CONF) + gallery_conf.update(examples_dir=tempfile.mkdtemp(), + gallery_dir=tempfile.mkdtemp()) + gallery_conf.update(kwargs) + return gallery_conf + + def test_pattern_matching(): """Test if only examples matching pattern are executed""" - examples_dir = tempfile.mkdtemp() - gallery_dir = tempfile.mkdtemp() - - gallery_conf = { - 'filename_pattern': re.escape(os.sep) + 'plot_0', - 'examples_dirs': examples_dir, - 'gallery_dirs': gallery_dir, - 'plot_gallery': True, - 'mod_example_dir': 'modules/generated', - 'doc_module': (), - 'reference_url': {}, - } + + gallery_conf = build_temp_setup( + filename_pattern=re.escape(os.sep) + 'plot_0') code_output = ('\n Out::\n' '\n' @@ -155,7 +158,8 @@ def test_pattern_matching(): encoding='utf-8') as f: f.write('\n'.join(CONTENT)) # generate rst file - sg.generate_file_rst(fname, gallery_dir, examples_dir, gallery_conf) + sg.generate_file_rst(fname, gallery_conf['gallery_dir'], + gallery_conf['examples_dir'], gallery_conf) # read rst file and check if it contains code output rst_fname = os.path.splitext(fname)[0] + '.rst' with codecs.open(os.path.join(gallery_dir, rst_fname), From 58ee7c0cfd9f582925000ebf9195b64528655b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 14 Feb 2016 20:43:23 +0100 Subject: [PATCH 07/60] Test single errored block run --- sphinx_gallery/tests/test_gen_rst.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index a415b9e86..df29c28b6 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -138,6 +138,27 @@ def build_temp_setup(**kwargs): gallery_conf.update(kwargs) return gallery_conf +def test_fail_example(): + """Test that failing examples are only executed until failing block""" + + gallery_conf = build_temp_setup(filename_pattern='raise.py') + + failing_code = CONTENT + ['#'*79, 'First_test_fail', '#'*79, 'second_fail'] + + with open(os.path.join(gallery_conf['examples_dir'], 'raise.py'), 'w') as f: + f.write('\n'.join(failing_code)) + + sg.generate_file_rst('raise.py', gallery_conf['gallery_dir'], + gallery_conf['examples_dir'], gallery_conf) + + # read rst file and check if it contains traceback output + with open(os.path.join(gallery_conf['gallery_dir'], 'raise.rst'), 'r') as f: + ex_failing_blocks = f.read().count('pytb') + if ex_failing_blocks == 0: + raise 'Did not run into errors in bad code' + elif ex_failing_blocks > 1: + raise 'Did not stop executing script after error' + def test_pattern_matching(): """Test if only examples matching pattern are executed""" From c079e249fd0fc97cbdc44a59ee0761d9372ec069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sat, 20 Feb 2016 16:19:18 +0100 Subject: [PATCH 08/60] Raise ValueError on test bad code --- sphinx_gallery/tests/test_gen_rst.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index df29c28b6..6fff6eb3a 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -155,9 +155,9 @@ def test_fail_example(): with open(os.path.join(gallery_conf['gallery_dir'], 'raise.rst'), 'r') as f: ex_failing_blocks = f.read().count('pytb') if ex_failing_blocks == 0: - raise 'Did not run into errors in bad code' + raise ValueError('Did not run into errors in bad code') elif ex_failing_blocks > 1: - raise 'Did not stop executing script after error' + raise ValueError('Did not stop executing script after error') def test_pattern_matching(): From e3a3678175f781174c5017220e640c131254c269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sat, 20 Feb 2016 16:51:53 +0100 Subject: [PATCH 09/60] Enable a set of expected to fail examples --- doc/conf.py | 1 + sphinx_gallery/gen_gallery.py | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 788b37e4e..76642f4e6 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -304,4 +304,5 @@ def setup(app): 'examples_dirs': examples_dirs, 'gallery_dirs': gallery_dirs, 'find_mayavi_figures': find_mayavi_figures, + 'examples_expected_to_fail': set(['../examples/plot_raise.py']) } diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 66b909102..a79943526 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -31,6 +31,7 @@ 'plot_gallery': True, 'abort_on_example_error': False, 'failed_examples': [], + 'examples_expected_to_fail': set(), } @@ -166,9 +167,19 @@ def exit_on_fail_examples(app, exception): return gallery_conf = app.config.sphinx_gallery_conf - if len(gallery_conf['failed_examples']): - sys.stderr.write("Failed examples:\n\n") - sys.stderr.write("\n".join(gallery_conf['failed_examples']) + '\n\n') + failed_examples = set(gallery_conf['failed_examples']) + ex_fail_examples = set(gallery_conf['examples_expected_to_fail']) + + unexpected_ex_fails = failed_examples.difference(ex_fail_examples) + if unexpected_ex_fails: + sys.stderr.write("Unexpected failing examples:\n\n") + sys.stderr.write("\n".join(unexpected_ex_fails) + '\n\n') + sys.exit(1) + + unexpected_ex_pass = ex_fail_examples.difference(failed_examples) + if unexpected_ex_pass: + sys.stderr.write("Examples that are not failing anymore:\n\n") + sys.stderr.write("\n".join(unexpected_ex_pass) + '\n\n') sys.exit(1) From 4d139b2cd9571721f66ba1831c317c783a8122d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sat, 20 Feb 2016 16:53:55 +0100 Subject: [PATCH 10/60] Change fail example message --- sphinx_gallery/gen_rst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 548c519ca..b9d7c1a55 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -531,7 +531,7 @@ def execute_script(code_block, example_globals, image_path, fig_count, formatted_exception = traceback.format_exc() sys.stderr.write(80 * '_' + '\n') - sys.stderr.write('%s is not compiling:' % src_file) + sys.stderr.write('%s failed to execute correctly:' % src_file) sys.stderr.write(formatted_exception) sys.stderr.write(80 * '_' + '\n') From 0490d485eff6bcc7080aed0e4e2a02037bec9993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sat, 20 Feb 2016 17:09:20 +0100 Subject: [PATCH 11/60] Categorize failing examples and give traceback --- sphinx_gallery/gen_gallery.py | 14 ++++++++++++-- sphinx_gallery/gen_rst.py | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index a79943526..665dd1bc6 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -30,7 +30,7 @@ # build options 'plot_gallery': True, 'abort_on_example_error': False, - 'failed_examples': [], + 'failed_examples': {}, 'examples_expected_to_fail': set(), } @@ -173,7 +173,17 @@ def exit_on_fail_examples(app, exception): unexpected_ex_fails = failed_examples.difference(ex_fail_examples) if unexpected_ex_fails: sys.stderr.write("Unexpected failing examples:\n\n") - sys.stderr.write("\n".join(unexpected_ex_fails) + '\n\n') + for fail_example in unexpected_ex_fails: + sys.stderr.write(fail_example + ' failed leaving traceback:\n') + sys.stderr.write(gallery_conf['failed_examples'][fail_example] +'\n') + sys.exit(1) + + still_ex_fails = failed_examples.intersection(ex_fail_examples) + if still_ex_fails: + sys.stderr.write("Known failing examples, still failing:\n\n") + for fail_example in still_ex_fails: + sys.stderr.write(fail_example + ' failed leaving traceback:\n') + sys.stderr.write(gallery_conf['failed_examples'][fail_example] +'\n') sys.exit(1) unexpected_ex_pass = ex_fail_examples.difference(failed_examples) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index b9d7c1a55..8649acc4d 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -549,7 +549,7 @@ def execute_script(code_block, example_globals, image_path, fig_count, if gallery_conf['abort_on_example_error']: raise # Stores failing file - gallery_conf['failed_examples'].append(src_file) + gallery_conf['failed_examples'].update({src_file: formatted_exception}) finally: os.chdir(cwd) From e21cea4ee6af30ad61f3f96654dfb2687dfab288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sat, 20 Feb 2016 17:18:35 +0100 Subject: [PATCH 12/60] Expected to fail examples do not exit 1 --- sphinx_gallery/gen_gallery.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 665dd1bc6..dc73518c1 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -184,7 +184,6 @@ def exit_on_fail_examples(app, exception): for fail_example in still_ex_fails: sys.stderr.write(fail_example + ' failed leaving traceback:\n') sys.stderr.write(gallery_conf['failed_examples'][fail_example] +'\n') - sys.exit(1) unexpected_ex_pass = ex_fail_examples.difference(failed_examples) if unexpected_ex_pass: From 87b5dcd8e4f32047fa366d78fb45b254c316e117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sat, 20 Feb 2016 17:25:28 +0100 Subject: [PATCH 13/60] Comment about fail example exit 1 --- CHANGES.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 1675f215c..fa1d9d785 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,9 +4,13 @@ Change Log git master ---------- -New features +New Features '''''''''''' +* End of build summary of failing examples with traceback. It is + possible to declare expected to fail examples, otherwise the build + exits with 1 and fails. + * Print aggregated and sorted list of computation times of all examples in the console during the build. * For examples that create multiple figures, set the thumbnail image. @@ -41,7 +45,7 @@ Example scripts are now available for download as IPython Notebooks `#75 `_ New features ------------- +'''''''''''' * Configurable filename pattern to select which example scripts are executed while building the Gallery From 7816bb22e6161c6d6241fccce41faed3e76e0425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sat, 20 Feb 2016 17:38:25 +0100 Subject: [PATCH 14/60] Configuration documentation about fail examples --- doc/advanced_configuration.rst | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/doc/advanced_configuration.rst b/doc/advanced_configuration.rst index d129d6b5d..a8dba81bc 100644 --- a/doc/advanced_configuration.rst +++ b/doc/advanced_configuration.rst @@ -267,7 +267,17 @@ failing code block. Refer to example :ref:`sphx_glr_auto_examples_plot_raise.py` to view the default behavior. -An extra functionality of Sphinx-Gallery is the early fail option. In +The build is also failed exiting with code 1 and giving you a summary +of the failed examples with their repective traceback. This way you +are aware of failing examples right after the build and can find them +easily. + +There are some additional options at your hand to deal with broken examples. + +Abort build on first fail +------------------------- + +Sphinx-Gallery provides the early fail option. In this mode the gallery build process breaks as soon as an exception occurs in the execution of the examples scripts. To activate this behavior you need to pass a flag at the build process. It can be done @@ -281,4 +291,27 @@ by including in your ``Makefile``:: Remember that for ``Makefile`` white space is significant and the indentation are tabs and not spaces +Don't fail the build on exit +---------------------------- + +It migth be the case that you want to keep the gallery even with +failed examples. Thus you can configure Sphinx-Gallery to allow +certain examples to fail and not to trow a failed build exit code 1 if +only known to fail examples have failed. For this you need to list all +the examples you want to allow to fail during build. Change your +`conf.py` accordingly: + + +.. code-block:: python + + sphinx_gallery_conf = { + ... + 'examples_expected_to_fail': ['../examples/plot_raise.py'] + } + +Here you list the examples you allow to fail during the build process, +keep in mind to specify the full relavite path from your `conf.py` to +the example script. + + .. _regular expressions: https://docs.python.org/2/library/re.html From d7ee1b69f25db59fe3a8527bc942b0798f6c2a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 6 Mar 2016 20:00:09 +0100 Subject: [PATCH 15/60] mark a file of broken example --- sphinx_gallery/gen_rst.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 8649acc4d..7b3ecc405 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -240,7 +240,8 @@ def extract_thumbnail_number(text): """ Pull out the thumbnail image number specified in the docstring. """ # check whether the user has specified a specific thumbnail image - pattr = re.compile("^\s*#\s*sphinx_gallery_thumbnail_number\s*=\s*([0-9]+)\s*$", flags=re.MULTILINE) + pattr = re.compile( + "^\s*#\s*sphinx_gallery_thumbnail_number\s*=\s*([0-9]+)\s*$", flags=re.MULTILINE) match = pattr.search(text) if match is None: @@ -251,6 +252,7 @@ def extract_thumbnail_number(text): return thumbnail_number + def extract_intro(filename): """ Extract the first paragraph of module-level docstring. max:95 char""" @@ -422,6 +424,11 @@ def save_thumbnail(thumbnail_image_path, base_image_name, gallery_conf): if os.path.exists(thumbnail_image_path): scale_image(thumbnail_image_path, thumb_file, 400, 280) + + elif os.path.exists(base_image_name.format('broken')): + broken_img = os.path.join(glr_path_static(), 'broken_example.png') + scale_image(broken_img, thumb_file, 200, 140) + elif not os.path.exists(thumb_file): # create something to replace the thumbnail default_thumb_file = os.path.join(glr_path_static(), 'no_image.png') @@ -538,10 +545,10 @@ def execute_script(code_block, example_globals, image_path, fig_count, figure_list = [] image_list = codestr2rst(formatted_exception, lang='pytb') - # Overrides the output thumbnail in the gallery for easy identification - broken_img = os.path.join(glr_path_static(), 'broken_example.png') - shutil.copyfile(broken_img, os.path.join(cwd, image_path.format(1))) - fig_count += 1 # raise count to avoid overwriting image + # Touches a broken image file + broken_img = image_path.format('broken') + if not os.path.exists(broken_img): + open(broken_img, 'w').close() # Breaks build on first example error # XXX This check can break during testing e.g. if you uncomment the From 3631b962cc96761f4dae576d227272a260281f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 6 Mar 2016 20:20:45 +0100 Subject: [PATCH 16/60] Image_path needs numbers to format --- sphinx_gallery/gen_rst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 7b3ecc405..c0c6eb85d 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -546,7 +546,7 @@ def execute_script(code_block, example_globals, image_path, fig_count, image_list = codestr2rst(formatted_exception, lang='pytb') # Touches a broken image file - broken_img = image_path.format('broken') + broken_img = os.path.join(cwd, image_path.format(-1)) if not os.path.exists(broken_img): open(broken_img, 'w').close() From 5562a469c493fa7f16e884f19f6d7399a022ffbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 6 Mar 2016 20:33:19 +0100 Subject: [PATCH 17/60] Check for failed example on last build plots are current verifies not to find image mark file of broken example to return True. If example has failed in previous builds, then plots are not current and the example is build from start. Fix #105 Fix #94 because first image is no longer overwritten --- sphinx_gallery/gen_rst.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index c0c6eb85d..d996116ef 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -312,6 +312,14 @@ def _plots_are_current(src_file, image_path): example""" has_image = os.path.exists(image_path) + + # if example failed on previous builds + broken_img = image_file.format(-1) + if os.path.exists(broken_img): + has_image = False + # to avoid considering example as failed on future builds + os.remove(broken_img) + src_file_changed = check_md5sum_change(src_file) return has_image and not src_file_changed From 9045a759259327ab49e78c7c2f34fd59b6c51f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 6 Mar 2016 21:38:09 +0100 Subject: [PATCH 18/60] Spellcheck advanced configuration --- doc/advanced_configuration.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/advanced_configuration.rst b/doc/advanced_configuration.rst index a8dba81bc..441a547b8 100644 --- a/doc/advanced_configuration.rst +++ b/doc/advanced_configuration.rst @@ -268,7 +268,7 @@ failing code block. Refer to example behavior. The build is also failed exiting with code 1 and giving you a summary -of the failed examples with their repective traceback. This way you +of the failed examples with their respective traceback. This way you are aware of failing examples right after the build and can find them easily. @@ -294,7 +294,7 @@ and not spaces Don't fail the build on exit ---------------------------- -It migth be the case that you want to keep the gallery even with +It might be the case that you want to keep the gallery even with failed examples. Thus you can configure Sphinx-Gallery to allow certain examples to fail and not to trow a failed build exit code 1 if only known to fail examples have failed. For this you need to list all @@ -310,7 +310,7 @@ the examples you want to allow to fail during build. Change your } Here you list the examples you allow to fail during the build process, -keep in mind to specify the full relavite path from your `conf.py` to +keep in mind to specify the full relative path from your `conf.py` to the example script. From 62b7d213dc4392c6f99818307f855d3a6f88ee6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 6 Mar 2016 21:40:21 +0100 Subject: [PATCH 19/60] Correct use of path join --- sphinx_gallery/gen_gallery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index dc73518c1..5646341c7 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -22,7 +22,7 @@ DEFAULT_GALLERY_CONF = { 'filename_pattern': re.escape(os.sep) + 'plot', - 'examples_dirs': '../examples', + 'examples_dirs': os.path.join('..', 'examples'), 'gallery_dirs': 'auto_examples', 'mod_example_dir': os.path.join('modules', 'generated'), 'doc_module': (), From 08012db0921cd8ab3d1b25a7471aa34fbeb499c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 6 Mar 2016 21:53:10 +0100 Subject: [PATCH 20/60] Pep8 into test function --- sphinx_gallery/tests/test_gen_rst.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 6fff6eb3a..b4d1927d3 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -136,14 +136,17 @@ def build_temp_setup(**kwargs): gallery_conf.update(examples_dir=tempfile.mkdtemp(), gallery_dir=tempfile.mkdtemp()) gallery_conf.update(kwargs) + return gallery_conf + def test_fail_example(): """Test that failing examples are only executed until failing block""" gallery_conf = build_temp_setup(filename_pattern='raise.py') - failing_code = CONTENT + ['#'*79, 'First_test_fail', '#'*79, 'second_fail'] + failing_code = CONTENT + ['#' * 79, + 'First_test_fail', '#' * 79, 'second_fail'] with open(os.path.join(gallery_conf['examples_dir'], 'raise.py'), 'w') as f: f.write('\n'.join(failing_code)) From 47d1c6ed28b1421f8926c373012e5d27fc35d2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Wed, 13 Apr 2016 00:47:31 +0200 Subject: [PATCH 21/60] Use config for tests --- sphinx_gallery/tests/test_gen_rst.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index b4d1927d3..3286005f2 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -178,7 +178,7 @@ def test_pattern_matching(): # create three files in tempdir (only one matches the pattern) fnames = ['plot_0.py', 'plot_1.py', 'plot_2.py'] for fname in fnames: - with codecs.open(os.path.join(examples_dir, fname), mode='w', + with codecs.open(os.path.join(gallery_conf['examples_dir'], fname), mode='w', encoding='utf-8') as f: f.write('\n'.join(CONTENT)) # generate rst file @@ -186,11 +186,11 @@ def test_pattern_matching(): gallery_conf['examples_dir'], gallery_conf) # read rst file and check if it contains code output rst_fname = os.path.splitext(fname)[0] + '.rst' - with codecs.open(os.path.join(gallery_dir, rst_fname), + with codecs.open(os.path.join(gallery_conf['gallery_dir'], rst_fname), mode='r', encoding='utf-8') as f: rst = f.read() if re.search(gallery_conf['filename_pattern'], - os.path.join(gallery_dir, rst_fname)): + os.path.join(gallery_conf['gallery_dir'], rst_fname)): assert_true(code_output in rst) else: assert_false(code_output in rst) From 1b3e3b048566868a64193dcb0ccec3c1efe450b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Wed, 13 Apr 2016 01:30:44 +0200 Subject: [PATCH 22/60] UTF-8 for tests --- sphinx_gallery/tests/test_gen_rst.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 3286005f2..59ad00a4f 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -148,14 +148,17 @@ def test_fail_example(): failing_code = CONTENT + ['#' * 79, 'First_test_fail', '#' * 79, 'second_fail'] - with open(os.path.join(gallery_conf['examples_dir'], 'raise.py'), 'w') as f: + with codecs.open(os.path.join(gallery_conf['examples_dir'], 'raise.py'), + mode='w', encoding='utf-8') as f: f.write('\n'.join(failing_code)) sg.generate_file_rst('raise.py', gallery_conf['gallery_dir'], gallery_conf['examples_dir'], gallery_conf) # read rst file and check if it contains traceback output - with open(os.path.join(gallery_conf['gallery_dir'], 'raise.rst'), 'r') as f: + + with codecs.open(os.path.join(gallery_conf['gallery_dir'], 'raise.rst'), + mode='r', encoding='utf-8') as f: ex_failing_blocks = f.read().count('pytb') if ex_failing_blocks == 0: raise ValueError('Did not run into errors in bad code') @@ -178,8 +181,8 @@ def test_pattern_matching(): # create three files in tempdir (only one matches the pattern) fnames = ['plot_0.py', 'plot_1.py', 'plot_2.py'] for fname in fnames: - with codecs.open(os.path.join(gallery_conf['examples_dir'], fname), mode='w', - encoding='utf-8') as f: + with codecs.open(os.path.join(gallery_conf['examples_dir'], fname), + mode='w', encoding='utf-8') as f: f.write('\n'.join(CONTENT)) # generate rst file sg.generate_file_rst(fname, gallery_conf['gallery_dir'], From 089bf922686f851eac2c5181ce62c929c1b38dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 13:28:16 +0200 Subject: [PATCH 23/60] Write md5 only after successful build --- sphinx_gallery/gen_rst.py | 10 ++++++---- sphinx_gallery/tests/test_gen_rst.py | 6 ++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index d996116ef..8c4369503 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -300,10 +300,6 @@ def check_md5sum_change(src_file): if src_md5 == ref_md5: src_file_changed = False - if src_file_changed: - with open(src_md5_file, 'w') as file_checksum: - file_checksum.write(src_md5) - return src_file_changed @@ -667,6 +663,12 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): example_rst += bcontent + '\n' example_nb.add_markdown_cell(text2string(bcontent)) + # Writes md5 checksum if example has build correctly + broken_img_mark = image_path_template.format(-1) + if not os.path.exists(broken_img_mark): + with open(example_file + '.md5', 'w') as file_checksum: + file_checksum.write(get_md5sum(example_file)) + thumbnail_image_path = image_path_template.format(thumbnail_number) save_thumbnail(thumbnail_image_path, base_image_name, gallery_conf) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 59ad00a4f..abd338126 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -123,10 +123,6 @@ def test_md5sums(): assert_equal('ea8a570e9f3afc0a7c3f2a17a48b8047', file_md5) # True because is a new file assert_true(sg.check_md5sum_change(f.name)) - # False because file has not changed since last check - assert_false(sg.check_md5sum_change(f.name)) - - os.remove(f.name + '.md5') def build_temp_setup(**kwargs): @@ -216,6 +212,7 @@ def test_ipy_notebook(): f.flush() assert_equal(json.load(f), example_nb.work_notebook) + def test_thumbnail_number(): # which plot to show as the thumbnail image for test_str in ['# sphinx_gallery_thumbnail_number= 2', @@ -230,6 +227,7 @@ def test_thumbnail_number(): thumbnail_number = sg.extract_thumbnail_number(content) assert_equal(thumbnail_number, 2) + def test_save_figures(): """Test file naming when saving figures. Requires mayavi.""" try: From 9e426286ea4ae3409daa6610220c92a917bdb7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 13:29:09 +0200 Subject: [PATCH 24/60] save failing image mark --- sphinx_gallery/gen_rst.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 8c4369503..a2d44850f 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -310,11 +310,11 @@ def _plots_are_current(src_file, image_path): has_image = os.path.exists(image_path) # if example failed on previous builds - broken_img = image_file.format(-1) - if os.path.exists(broken_img): + broken_img_mark = image_path.format(-1) + if os.path.exists(broken_img_mark): has_image = False # to avoid considering example as failed on future builds - os.remove(broken_img) + os.remove(broken_img_mark) src_file_changed = check_md5sum_change(src_file) @@ -426,13 +426,14 @@ def save_thumbnail(thumbnail_image_path, base_image_name, gallery_conf): thumb_file = os.path.join(thumb_dir, 'sphx_glr_%s_thumb.png' % base_image_name) - if os.path.exists(thumbnail_image_path): - scale_image(thumbnail_image_path, thumb_file, 400, 280) - - elif os.path.exists(base_image_name.format('broken')): + broken_img_mark = 'sphx_glr_' + base_image_name + '_-01.png' + if os.path.exists(base_image_name.format('broken')): broken_img = os.path.join(glr_path_static(), 'broken_example.png') scale_image(broken_img, thumb_file, 200, 140) + elif os.path.exists(thumbnail_image_path): + scale_image(thumbnail_image_path, thumb_file, 400, 280) + elif not os.path.exists(thumb_file): # create something to replace the thumbnail default_thumb_file = os.path.join(glr_path_static(), 'no_image.png') @@ -550,9 +551,9 @@ def execute_script(code_block, example_globals, image_path, fig_count, image_list = codestr2rst(formatted_exception, lang='pytb') # Touches a broken image file - broken_img = os.path.join(cwd, image_path.format(-1)) - if not os.path.exists(broken_img): - open(broken_img, 'w').close() + broken_img_mark = os.path.join(cwd, image_path.format(-1)) + if not os.path.exists(broken_img_mark): + open(broken_img_mark, 'w').close() # Breaks build on first example error # XXX This check can break during testing e.g. if you uncomment the From 41d7477363f308794ef2afcd09b76b5c40c09b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 13:50:09 +0200 Subject: [PATCH 25/60] Fix Broken image thumbnail display --- sphinx_gallery/gen_rst.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index a2d44850f..3f344b414 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -303,14 +303,14 @@ def check_md5sum_change(src_file): return src_file_changed -def _plots_are_current(src_file, image_path): +def _plots_are_current(src_file, image_path_template): """Test existence of image file and no change in md5sum of example""" - has_image = os.path.exists(image_path) + has_image = os.path.exists(image_path_template.format(1)) # if example failed on previous builds - broken_img_mark = image_path.format(-1) + broken_img_mark = image_path_template.format(-1) if os.path.exists(broken_img_mark): has_image = False # to avoid considering example as failed on future builds @@ -426,8 +426,9 @@ def save_thumbnail(thumbnail_image_path, base_image_name, gallery_conf): thumb_file = os.path.join(thumb_dir, 'sphx_glr_%s_thumb.png' % base_image_name) - broken_img_mark = 'sphx_glr_' + base_image_name + '_-01.png' - if os.path.exists(base_image_name.format('broken')): + broken_img_mark = os.path.join(os.path.dirname( + thumbnail_image_path), 'sphx_glr_' + base_image_name + '_-01.png') + if os.path.exists(broken_img_mark): broken_img = os.path.join(glr_path_static(), 'broken_example.png') scale_image(broken_img, thumb_file, 200, 140) @@ -602,8 +603,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): for blabel, bcontent in script_blocks if blabel == 'code']) - first_image_path = image_path_template.format(1) - if _plots_are_current(example_file, first_image_path): + if _plots_are_current(example_file, image_path_template): return amount_of_code, 0 time_elapsed = 0 From 8cb59d554a248412d88d2d37212ae475f71693cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 14:29:25 +0200 Subject: [PATCH 26/60] Exit With ValueError on failed examples end report --- sphinx_gallery/gen_gallery.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 5646341c7..580be606b 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -16,6 +16,7 @@ import re import os import sys +import warnings from . import glr_path_static from .gen_rst import generate_dir_rst, SPHX_GLR_SIG from .docs_resolv import embed_code_links @@ -171,25 +172,28 @@ def exit_on_fail_examples(app, exception): ex_fail_examples = set(gallery_conf['examples_expected_to_fail']) unexpected_ex_fails = failed_examples.difference(ex_fail_examples) + fail_msgs = [] if unexpected_ex_fails: - sys.stderr.write("Unexpected failing examples:\n\n") + fail_msgs.append("Unexpected failing examples:") for fail_example in unexpected_ex_fails: - sys.stderr.write(fail_example + ' failed leaving traceback:\n') - sys.stderr.write(gallery_conf['failed_examples'][fail_example] +'\n') - sys.exit(1) + fail_msgs.append(fail_example + ' failed leaving traceback:\n' + + gallery_conf['failed_examples'][fail_example] + '\n') still_ex_fails = failed_examples.intersection(ex_fail_examples) if still_ex_fails: - sys.stderr.write("Known failing examples, still failing:\n\n") + fail_msgs.append("Known failing examples, still failing:") for fail_example in still_ex_fails: - sys.stderr.write(fail_example + ' failed leaving traceback:\n') - sys.stderr.write(gallery_conf['failed_examples'][fail_example] +'\n') + fail_msgs.append(fail_example + ' failed leaving traceback:\n' + + gallery_conf['failed_examples'][fail_example] + '\n') unexpected_ex_pass = ex_fail_examples.difference(failed_examples) if unexpected_ex_pass: - sys.stderr.write("Examples that are not failing anymore:\n\n") - sys.stderr.write("\n".join(unexpected_ex_pass) + '\n\n') - sys.exit(1) + fail_msgs.append("Examples that are not failing anymore:\n" + "\n".join(unexpected_ex_pass)) + + if fail_msgs: + raise ValueError("Not all Gallery example builds were successful\n\n" + + "\n".join(fail_msgs) + "-" * 79) def setup(app): From 2efcb11e227cb1eaee94612444d80d5acd926316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 14:34:08 +0200 Subject: [PATCH 27/60] Use warnings for failed example --- sphinx_gallery/gen_rst.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 3f344b414..e4e98af07 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -543,10 +543,10 @@ def execute_script(code_block, example_globals, image_path, fig_count, except Exception: formatted_exception = traceback.format_exc() - sys.stderr.write(80 * '_' + '\n') - sys.stderr.write('%s failed to execute correctly:' % src_file) - sys.stderr.write(formatted_exception) - sys.stderr.write(80 * '_' + '\n') + fail_example_warning = 80 * '_' + '\n' + \ + '%s failed to execute correctly:' % src_file + \ + formatted_exception + 80 * '_' + '\n' + warnings.warn(fail_example_warning) figure_list = [] image_list = codestr2rst(formatted_exception, lang='pytb') From d9d5262a2ee510a4e077bd84bd48f486b187f27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 14:40:07 +0200 Subject: [PATCH 28/60] Change ordering of end warn messages --- sphinx_gallery/gen_gallery.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 580be606b..2a8c9d2ac 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -171,6 +171,15 @@ def exit_on_fail_examples(app, exception): failed_examples = set(gallery_conf['failed_examples']) ex_fail_examples = set(gallery_conf['examples_expected_to_fail']) + still_ex_fails = failed_examples.intersection(ex_fail_examples) + expected_fail_msg = [] + if still_ex_fails: + expected_fail_msg.append("Known failing examples, still failing:") + for fail_example in still_ex_fails: + expected_fail_msg.append(fail_example + ' failed leaving traceback:\n' + + gallery_conf['failed_examples'][fail_example] + '\n') + warnings.warn("\n".join(expected_fail_msg)) + unexpected_ex_fails = failed_examples.difference(ex_fail_examples) fail_msgs = [] if unexpected_ex_fails: @@ -179,13 +188,6 @@ def exit_on_fail_examples(app, exception): fail_msgs.append(fail_example + ' failed leaving traceback:\n' + gallery_conf['failed_examples'][fail_example] + '\n') - still_ex_fails = failed_examples.intersection(ex_fail_examples) - if still_ex_fails: - fail_msgs.append("Known failing examples, still failing:") - for fail_example in still_ex_fails: - fail_msgs.append(fail_example + ' failed leaving traceback:\n' + - gallery_conf['failed_examples'][fail_example] + '\n') - unexpected_ex_pass = ex_fail_examples.difference(failed_examples) if unexpected_ex_pass: fail_msgs.append("Examples that are not failing anymore:\n" From 22d2366675e0dd081d1f587f65902836dac5be1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 14:45:27 +0200 Subject: [PATCH 29/60] PY2.6 fix example --- examples/plot_quantum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/plot_quantum.py b/examples/plot_quantum.py index 527a64110..18300ebac 100644 --- a/examples/plot_quantum.py +++ b/examples/plot_quantum.py @@ -60,7 +60,7 @@ for b in [10, 20, 30]: n = 2 * (np.exp(b * (mu - 1)) + np.exp(b * (2 * mu - 3))) / \ (1 + np.exp(b * (mu - 1)) * (2 + np.exp(b * (mu - 2)))) - plt.plot(mu, n, label=r"$\beta={}$".format(b)) + plt.plot(mu, n, label=r"$\beta={0}$".format(b)) plt.xlabel(r'$\mu$ ($\epsilon=1$, $U=1$)') plt.ylabel(r'$\langle N \rangle=\langle n_\uparrow \rangle+\langle n_\downarrow\rangle$') plt.legend(loc=0) From 185944a434825ffbf0119f597dd03bd8460ba06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Apr 2016 14:51:30 +0200 Subject: [PATCH 30/60] Consistent spelling in changes --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index fa1d9d785..ded52cbe5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,7 @@ Change Log git master ---------- -New Features +New features '''''''''''' * End of build summary of failing examples with traceback. It is From 187476192c2ac2eb993ad640d1887473d81bd109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 1 May 2016 23:56:03 +0200 Subject: [PATCH 31/60] Address naming convention comments --- doc/advanced_configuration.rst | 8 ++++---- doc/conf.py | 4 ++-- sphinx_gallery/gen_gallery.py | 19 +++++++++---------- sphinx_gallery/gen_rst.py | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/doc/advanced_configuration.rst b/doc/advanced_configuration.rst index 441a547b8..ddedce8b1 100644 --- a/doc/advanced_configuration.rst +++ b/doc/advanced_configuration.rst @@ -55,11 +55,11 @@ you would do: } Here, one should escape the dot ``'\.'`` as otherwise python `regular expressions`_ matches any character. Nevertheless, as -one is targetting a specific file, it is most certainly going to match the dot in the filename. +one is targeting a specific file, it is most certainly going to match the dot in the filename. Similarly, to build only examples in a specific directory, you can do: -.. code-blocK:: python +.. code-block:: python sphinx_gallery_conf = { 'filename_pattern' : '/directory/plot_' @@ -296,7 +296,7 @@ Don't fail the build on exit It might be the case that you want to keep the gallery even with failed examples. Thus you can configure Sphinx-Gallery to allow -certain examples to fail and not to trow a failed build exit code 1 if +certain examples to fail and not to throw a failed build exit code 1 if only known to fail examples have failed. For this you need to list all the examples you want to allow to fail during build. Change your `conf.py` accordingly: @@ -306,7 +306,7 @@ the examples you want to allow to fail during build. Change your sphinx_gallery_conf = { ... - 'examples_expected_to_fail': ['../examples/plot_raise.py'] + 'expected_failing_examples': ['../examples/plot_raise.py'] } Here you list the examples you allow to fail during the build process, diff --git a/doc/conf.py b/doc/conf.py index 76642f4e6..2ecdd9ce6 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -304,5 +304,5 @@ def setup(app): 'examples_dirs': examples_dirs, 'gallery_dirs': gallery_dirs, 'find_mayavi_figures': find_mayavi_figures, - 'examples_expected_to_fail': set(['../examples/plot_raise.py']) - } + 'expected_failing_examples': set(['../examples/plot_raise.py']) +} diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 2a8c9d2ac..28dd3ea0b 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -15,7 +15,6 @@ import copy import re import os -import sys import warnings from . import glr_path_static from .gen_rst import generate_dir_rst, SPHX_GLR_SIG @@ -31,8 +30,8 @@ # build options 'plot_gallery': True, 'abort_on_example_error': False, - 'failed_examples': {}, - 'examples_expected_to_fail': set(), + 'failing_examples': {}, + 'expected_failing_examples': set(), } @@ -168,27 +167,27 @@ def exit_on_fail_examples(app, exception): return gallery_conf = app.config.sphinx_gallery_conf - failed_examples = set(gallery_conf['failed_examples']) - ex_fail_examples = set(gallery_conf['examples_expected_to_fail']) + failing_examples = set(gallery_conf['failing_examples']) + ex_fail_examples = set(gallery_conf['expected_failing_examples']) - still_ex_fails = failed_examples.intersection(ex_fail_examples) + still_ex_fails = failing_examples.intersection(ex_fail_examples) expected_fail_msg = [] if still_ex_fails: expected_fail_msg.append("Known failing examples, still failing:") for fail_example in still_ex_fails: expected_fail_msg.append(fail_example + ' failed leaving traceback:\n' + - gallery_conf['failed_examples'][fail_example] + '\n') + gallery_conf['failing_examples'][fail_example] + '\n') warnings.warn("\n".join(expected_fail_msg)) - unexpected_ex_fails = failed_examples.difference(ex_fail_examples) + unexpected_ex_fails = failing_examples.difference(ex_fail_examples) fail_msgs = [] if unexpected_ex_fails: fail_msgs.append("Unexpected failing examples:") for fail_example in unexpected_ex_fails: fail_msgs.append(fail_example + ' failed leaving traceback:\n' + - gallery_conf['failed_examples'][fail_example] + '\n') + gallery_conf['failing_examples'][fail_example] + '\n') - unexpected_ex_pass = ex_fail_examples.difference(failed_examples) + unexpected_ex_pass = ex_fail_examples.difference(failing_examples) if unexpected_ex_pass: fail_msgs.append("Examples that are not failing anymore:\n" "\n".join(unexpected_ex_pass)) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index e4e98af07..c8e29c214 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -495,7 +495,7 @@ def execute_script(code_block, example_globals, image_path, fig_count, time_elapsed = 0 stdout = '' - if src_file in gallery_conf['failed_examples']: + if src_file in gallery_conf['failing_examples']: return '', 0, 0 # We need to execute the code @@ -562,7 +562,7 @@ def execute_script(code_block, example_globals, image_path, fig_count, if gallery_conf['abort_on_example_error']: raise # Stores failing file - gallery_conf['failed_examples'].update({src_file: formatted_exception}) + gallery_conf['failing_examples'][src_file] = formatted_exception finally: os.chdir(cwd) From 5a4cceac37d6aced9aab0909a93cc415707558bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Mon, 2 May 2016 00:22:24 +0200 Subject: [PATCH 32/60] Drop image existence check to validate build Because the md5sum file is written only when an example has been correctly build, only that check is needed. --- sphinx_gallery/gen_rst.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index c8e29c214..9a4fa51ef 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -304,21 +304,18 @@ def check_md5sum_change(src_file): def _plots_are_current(src_file, image_path_template): - """Test existence of image file and no change in md5sum of - example""" - - has_image = os.path.exists(image_path_template.format(1)) + """Test for broken image file and checks md5sum changes""" # if example failed on previous builds broken_img_mark = image_path_template.format(-1) if os.path.exists(broken_img_mark): - has_image = False # to avoid considering example as failed on future builds os.remove(broken_img_mark) + return False src_file_changed = check_md5sum_change(src_file) - return has_image and not src_file_changed + return not src_file_changed def save_figures(image_path, fig_count, gallery_conf): From 5ed2859ee2315cf8f1a65987417349a60b1cc37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 8 May 2016 23:48:46 +0200 Subject: [PATCH 33/60] Remove Broken image tag file It is only necessary to have the md5sum check to verify successful builds. The failing_examples list hold the examples that need the broken thumbnail. --- sphinx_gallery/gen_gallery.py | 2 +- sphinx_gallery/gen_rst.py | 43 +++++++--------------------- sphinx_gallery/tests/test_gen_rst.py | 4 +-- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 28dd3ea0b..7b7001ea2 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -189,7 +189,7 @@ def exit_on_fail_examples(app, exception): unexpected_ex_pass = ex_fail_examples.difference(failing_examples) if unexpected_ex_pass: - fail_msgs.append("Examples that are not failing anymore:\n" + fail_msgs.append("Examples that are not failing anymore:\n" + "\n".join(unexpected_ex_pass)) if fail_msgs: diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 9a4fa51ef..3c5ecfca1 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -287,35 +287,21 @@ def get_md5sum(src_file): return src_md5 -def check_md5sum_change(src_file): - """Returns True if src_file has a different md5sum""" +def md5sum_is_current(src_file): + """Returns True if src_file has the on disk stored md5sum""" src_md5 = get_md5sum(src_file) src_md5_file = src_file + '.md5' - src_file_changed = True if os.path.exists(src_md5_file): with open(src_md5_file, 'r') as file_checksum: ref_md5 = file_checksum.read() if src_md5 == ref_md5: - src_file_changed = False + return True + else: + os.remove(src_md5_file) - return src_file_changed - - -def _plots_are_current(src_file, image_path_template): - """Test for broken image file and checks md5sum changes""" - - # if example failed on previous builds - broken_img_mark = image_path_template.format(-1) - if os.path.exists(broken_img_mark): - # to avoid considering example as failed on future builds - os.remove(broken_img_mark) - return False - - src_file_changed = check_md5sum_change(src_file) - - return not src_file_changed + return False def save_figures(image_path, fig_count, gallery_conf): @@ -414,18 +400,17 @@ def scale_image(in_fname, out_fname, max_width, max_height): generated images') -def save_thumbnail(thumbnail_image_path, base_image_name, gallery_conf): +def save_thumbnail(thumbnail_image_path, src_file, gallery_conf): """Save the thumbnail image""" thumb_dir = os.path.join(os.path.dirname(thumbnail_image_path), 'thumb') if not os.path.exists(thumb_dir): os.makedirs(thumb_dir) + base_image_name = os.path.splitext(os.path.basename(src_file))[0] thumb_file = os.path.join(thumb_dir, 'sphx_glr_%s_thumb.png' % base_image_name) - broken_img_mark = os.path.join(os.path.dirname( - thumbnail_image_path), 'sphx_glr_' + base_image_name + '_-01.png') - if os.path.exists(broken_img_mark): + if src_file in gallery_conf['failing_examples']: broken_img = os.path.join(glr_path_static(), 'broken_example.png') scale_image(broken_img, thumb_file, 200, 140) @@ -548,11 +533,6 @@ def execute_script(code_block, example_globals, image_path, fig_count, figure_list = [] image_list = codestr2rst(formatted_exception, lang='pytb') - # Touches a broken image file - broken_img_mark = os.path.join(cwd, image_path.format(-1)) - if not os.path.exists(broken_img_mark): - open(broken_img_mark, 'w').close() - # Breaks build on first example error # XXX This check can break during testing e.g. if you uncomment the # `raise RuntimeError` by the `my_stdout` call, maybe use `.get()`? @@ -600,7 +580,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): for blabel, bcontent in script_blocks if blabel == 'code']) - if _plots_are_current(example_file, image_path_template): + if md5sum_is_current(example_file): return amount_of_code, 0 time_elapsed = 0 @@ -662,8 +642,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): example_nb.add_markdown_cell(text2string(bcontent)) # Writes md5 checksum if example has build correctly - broken_img_mark = image_path_template.format(-1) - if not os.path.exists(broken_img_mark): + if not src_file in gallery_conf['failing_examples']: with open(example_file + '.md5', 'w') as file_checksum: file_checksum.write(get_md5sum(example_file)) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index abd338126..90390142c 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -121,8 +121,8 @@ def test_md5sums(): file_md5 = sg.get_md5sum(f.name) # verify correct md5sum assert_equal('ea8a570e9f3afc0a7c3f2a17a48b8047', file_md5) - # True because is a new file - assert_true(sg.check_md5sum_change(f.name)) + # False because is a new file + assert_false(sg.md5sum_is_current(f.name)) def build_temp_setup(**kwargs): From c14881620043dff0fafd1b3ddcab006ed8912433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Mon, 9 May 2016 00:27:09 +0200 Subject: [PATCH 34/60] Update raise example comments Execution of blocks terminates after first failure --- examples/plot_raise.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/plot_raise.py b/examples/plot_raise.py index 88a05deee..d20131ae8 100644 --- a/examples/plot_raise.py +++ b/examples/plot_raise.py @@ -13,10 +13,10 @@ iae ############################################################################### -# Sphinx gallery as it executes scripts by block will continue -# evaluating the script after exceptions, but there is no warranty -# figure ordering will continue to match block's code. Anyway when the -# script is broken, you should try to fix it first. +# Sphinx gallery will stop executing the remaining code blocks after +# the exception has occurred in the example script. Nevertheless the +# html will still render all the example annotated text and +# code blocks, just no output. # Code source: Óscar Nájera # License: BSD 3 clause From be019e20e5800237d3bed4d53479b7626747c59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 12 May 2016 18:47:39 +0200 Subject: [PATCH 35/60] Address comments --- sphinx_gallery/gen_gallery.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 7b7001ea2..00601d4a0 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -161,7 +161,7 @@ def touch_empty_backreferences(app, what, name, obj, options, lines): open(examples_path, 'w').close() -def exit_on_fail_examples(app, exception): +def sumarize_failing_examples(app, exception): """Embed hyperlinks to documentation into example code""" if exception is not None: return @@ -177,7 +177,7 @@ def exit_on_fail_examples(app, exception): for fail_example in still_ex_fails: expected_fail_msg.append(fail_example + ' failed leaving traceback:\n' + gallery_conf['failing_examples'][fail_example] + '\n') - warnings.warn("\n".join(expected_fail_msg)) + print("\n".join(expected_fail_msg)) unexpected_ex_fails = failing_examples.difference(ex_fail_examples) fail_msgs = [] @@ -209,7 +209,7 @@ def setup(app): app.connect('builder-inited', generate_gallery_rst) - app.connect('build-finished', exit_on_fail_examples) + app.connect('build-finished', sumarize_failing_examples) app.connect('build-finished', embed_code_links) From 03e94880411c4eda0f5f55b404d293a7487698a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Wed, 1 Jun 2016 19:35:48 +0200 Subject: [PATCH 36/60] Fix documentation content --- CHANGES.rst | 11 ++++++----- doc/advanced_configuration.rst | 7 +++---- doc/conf.py | 2 +- examples/plot_raise.py | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index ded52cbe5..21efea469 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,11 +6,12 @@ git master New features '''''''''''' - -* End of build summary of failing examples with traceback. It is - possible to declare expected to fail examples, otherwise the build - exits with 1 and fails. - +* Summary of failing examples with traceback at the end of the sphinx + build. By default the build exits with a 1 exit code if an example + has failed. A list of of examples that are expected to fail can be + defined in `conf.py` and exit the build with 0 + exitcode. Alternatively it is possible to exit the build as soon as + one example has failed. * Print aggregated and sorted list of computation times of all examples in the console during the build. * For examples that create multiple figures, set the thumbnail image. diff --git a/doc/advanced_configuration.rst b/doc/advanced_configuration.rst index ddedce8b1..7f1ec6bb4 100644 --- a/doc/advanced_configuration.rst +++ b/doc/advanced_configuration.rst @@ -296,10 +296,9 @@ Don't fail the build on exit It might be the case that you want to keep the gallery even with failed examples. Thus you can configure Sphinx-Gallery to allow -certain examples to fail and not to throw a failed build exit code 1 if -only known to fail examples have failed. For this you need to list all -the examples you want to allow to fail during build. Change your -`conf.py` accordingly: +certain examples to fail and still exit with a 0 exit code. For this +you need to list all the examples you want to allow to fail during +build. Change your `conf.py` accordingly: .. code-block:: python diff --git a/doc/conf.py b/doc/conf.py index 2ecdd9ce6..8003622ad 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -304,5 +304,5 @@ def setup(app): 'examples_dirs': examples_dirs, 'gallery_dirs': gallery_dirs, 'find_mayavi_figures': find_mayavi_figures, - 'expected_failing_examples': set(['../examples/plot_raise.py']) + 'expected_failing_examples': ['../examples/plot_raise.py'] } diff --git a/examples/plot_raise.py b/examples/plot_raise.py index d20131ae8..db504a83c 100644 --- a/examples/plot_raise.py +++ b/examples/plot_raise.py @@ -16,7 +16,7 @@ # Sphinx gallery will stop executing the remaining code blocks after # the exception has occurred in the example script. Nevertheless the # html will still render all the example annotated text and -# code blocks, just no output. +# code blocks, but no output will be shown. # Code source: Óscar Nájera # License: BSD 3 clause From 760e45fff71b376b858725af107c135ae78ef3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Wed, 1 Jun 2016 19:45:40 +0200 Subject: [PATCH 37/60] Address comments for gen_gallery and gen_rst --- sphinx_gallery/gen_gallery.py | 19 ++++++++++--------- sphinx_gallery/gen_rst.py | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 00601d4a0..32bdf3a8b 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -74,7 +74,6 @@ def generate_gallery_rst(app): gallery_conf = copy.deepcopy(DEFAULT_GALLERY_CONF) gallery_conf.update(app.config.sphinx_gallery_conf) gallery_conf.update(plot_gallery=plot_gallery) - gallery_conf.update(failed_examples=[]) gallery_conf.update( abort_on_example_error=app.builder.config.abort_on_example_error) @@ -168,18 +167,20 @@ def sumarize_failing_examples(app, exception): gallery_conf = app.config.sphinx_gallery_conf failing_examples = set(gallery_conf['failing_examples']) - ex_fail_examples = set(gallery_conf['expected_failing_examples']) + expected_failing_examples = set(gallery_conf['expected_failing_examples']) - still_ex_fails = failing_examples.intersection(ex_fail_examples) + still_failing_examples = failing_examples.intersection( + expected_failing_examples) expected_fail_msg = [] - if still_ex_fails: + if still_failing_examples: expected_fail_msg.append("Known failing examples, still failing:") - for fail_example in still_ex_fails: + for fail_example in still_failing_examples: expected_fail_msg.append(fail_example + ' failed leaving traceback:\n' + gallery_conf['failing_examples'][fail_example] + '\n') print("\n".join(expected_fail_msg)) - unexpected_ex_fails = failing_examples.difference(ex_fail_examples) + unexpected_ex_fails = failing_examples.difference( + expected_failing_examples) fail_msgs = [] if unexpected_ex_fails: fail_msgs.append("Unexpected failing examples:") @@ -187,14 +188,14 @@ def sumarize_failing_examples(app, exception): fail_msgs.append(fail_example + ' failed leaving traceback:\n' + gallery_conf['failing_examples'][fail_example] + '\n') - unexpected_ex_pass = ex_fail_examples.difference(failing_examples) + unexpected_ex_pass = expected_failing_examples.difference(failing_examples) if unexpected_ex_pass: fail_msgs.append("Examples that are not failing anymore:\n" + "\n".join(unexpected_ex_pass)) if fail_msgs: - raise ValueError("Not all Gallery example builds were successful\n\n" + - "\n".join(fail_msgs) + "-" * 79) + raise ValueError("Here is a summary of the problems encountered when" + "running the examples\n\n" + "\n".join(fail_msgs) + "-" * 79) def setup(app): diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 3c5ecfca1..b11d5e13e 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -288,7 +288,7 @@ def get_md5sum(src_file): def md5sum_is_current(src_file): - """Returns True if src_file has the on disk stored md5sum""" + """Returns True if src_file has the same md5 hash as the one stored on disk""" src_md5 = get_md5sum(src_file) From b930d1ccdf7d99950f0ebb6969904c7c093e8df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Wed, 1 Jun 2016 20:29:02 +0200 Subject: [PATCH 38/60] increase tests --- sphinx_gallery/tests/test_gen_rst.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 90390142c..d60e69468 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -123,10 +123,15 @@ def test_md5sums(): assert_equal('ea8a570e9f3afc0a7c3f2a17a48b8047', file_md5) # False because is a new file assert_false(sg.md5sum_is_current(f.name)) + # Write md5sum to file to check is current + with open(f.name + '.md5', 'w') as file_checksum: + file_checksum.write(file_md5) + assert_true(sg.md5sum_is_current(f.name)) + os.remove(f.name + '.md5') -def build_temp_setup(**kwargs): - """Sets a test build up""" +def build_test_configuration(**kwargs): + """Sets up a test sphinx-gallery configuration""" gallery_conf = copy.deepcopy(gen_gallery.DEFAULT_GALLERY_CONF) gallery_conf.update(examples_dir=tempfile.mkdtemp(), @@ -139,7 +144,7 @@ def build_temp_setup(**kwargs): def test_fail_example(): """Test that failing examples are only executed until failing block""" - gallery_conf = build_temp_setup(filename_pattern='raise.py') + gallery_conf = build_test_configuration(filename_pattern='raise.py') failing_code = CONTENT + ['#' * 79, 'First_test_fail', '#' * 79, 'second_fail'] @@ -165,7 +170,7 @@ def test_fail_example(): def test_pattern_matching(): """Test if only examples matching pattern are executed""" - gallery_conf = build_temp_setup( + gallery_conf = build_test_configuration( filename_pattern=re.escape(os.sep) + 'plot_0') code_output = ('\n Out::\n' From 5125065533121b322e007d547ba5a18214ddeeb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 21:10:46 +0200 Subject: [PATCH 39/60] Address comments --- sphinx_gallery/gen_rst.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index b11d5e13e..371d38ee7 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -298,8 +298,6 @@ def md5sum_is_current(src_file): ref_md5 = file_checksum.read() if src_md5 == ref_md5: return True - else: - os.remove(src_md5_file) return False @@ -471,12 +469,13 @@ def generate_dir_rst(src_dir, target_dir, gallery_conf, seen_backrefs): return fhindex, computation_times -def execute_script(code_block, example_globals, image_path, fig_count, - src_file, gallery_conf): +def execute_codeblock(code_block, example_globals, image_path, fig_count, + src_file, gallery_conf): """Executes the code block of the example file""" time_elapsed = 0 stdout = '' + # If the example is marked as failing skip executing its blocks if src_file in gallery_conf['failing_examples']: return '', 0, 0 @@ -609,12 +608,12 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): is_example_notebook_like = len(script_blocks) > 2 for blabel, bcontent in script_blocks: if blabel == 'code': - code_output, rtime, fig_count = execute_script(bcontent, - example_globals, - image_path_template, - fig_count, - src_file, - gallery_conf) + code_output, rtime, fig_count = execute_codeblock(bcontent, + example_globals, + image_path_template, + fig_count, + src_file, + gallery_conf) time_elapsed += rtime example_nb.add_code_cell(bcontent) From 41773a039f536f0383e66106a359141a0c747b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 21:30:48 +0200 Subject: [PATCH 40/60] Fix broken thumbnail issue Reminder to add test --- sphinx_gallery/gen_rst.py | 2 +- sphinx_gallery/tests/test_gen_rst.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 371d38ee7..3bede183f 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -646,7 +646,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): file_checksum.write(get_md5sum(example_file)) thumbnail_image_path = image_path_template.format(thumbnail_number) - save_thumbnail(thumbnail_image_path, base_image_name, gallery_conf) + save_thumbnail(thumbnail_image_path, src_file, gallery_conf) time_m, time_s = divmod(time_elapsed, 60) example_nb.save_file() diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index d60e69468..312302b7e 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -259,3 +259,5 @@ def test_save_figures(): assert fig_list[1].endswith('image4.png') shutil.rmtree(examples_dir) + +# TODO: test that broken thumbnail does appear when needed From 3fa7a37f3824baf2493d56fc99b80dd3d24b5d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 21:37:44 +0200 Subject: [PATCH 41/60] Update generate_file_rst docstring --- sphinx_gallery/gen_rst.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 3bede183f..671a4dc78 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -551,10 +551,14 @@ def execute_codeblock(code_block, example_globals, image_path, fig_count, def generate_file_rst(fname, target_dir, src_dir, gallery_conf): - """ Generate the rst file for a given example. + """Generate the rst file for a given example. - Returns the amout of code (in characters) of the corresponding - files. + Returns + ------- + amount_of_code: int + character count of the corresponding python script in file + time_elapsed: float + seconds required to run the script """ src_file = os.path.join(src_dir, fname) From b6cc8e6ece6d59160b270f5c8ad7e133dafd942e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 21:47:17 +0200 Subject: [PATCH 42/60] Use napoleon extension for documenting docstrings For the online documentation accept numpy docstring style --- doc/conf.py | 24 +++++++++++++----------- sphinx_gallery/gen_rst.py | 5 +++-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 8003622ad..04aad1334 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -32,6 +32,7 @@ # ones. extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', @@ -114,6 +115,7 @@ # a list of builtin themes. html_theme = 'default' + def setup(app): app.add_stylesheet('theme_override.css') @@ -199,22 +201,22 @@ def setup(app): # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'Sphinx-Gallery.tex', u'Sphinx-Gallery Documentation', - u'Óscar Nájera', 'manual'), + ('index', 'Sphinx-Gallery.tex', u'Sphinx-Gallery Documentation', + u'Óscar Nájera', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -257,9 +259,9 @@ def setup(app): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'Sphinx-Gallery', u'Sphinx-Gallery Documentation', - u'Óscar Nájera', 'Sphinx-Gallery', 'One line description of project.', - 'Miscellaneous'), + ('index', 'Sphinx-Gallery', u'Sphinx-Gallery Documentation', + u'Óscar Nájera', 'Sphinx-Gallery', 'One line description of project.', + 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 671a4dc78..d0113448e 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -555,9 +555,10 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): Returns ------- - amount_of_code: int + + amount_of_code : int character count of the corresponding python script in file - time_elapsed: float + time_elapsed : float seconds required to run the script """ From ce70a5809bcb035294b1fda43a68c70299326b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 22:00:26 +0200 Subject: [PATCH 43/60] regex with raw string --- sphinx_gallery/gen_rst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index d0113448e..3fb58e945 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -241,7 +241,7 @@ def extract_thumbnail_number(text): # check whether the user has specified a specific thumbnail image pattr = re.compile( - "^\s*#\s*sphinx_gallery_thumbnail_number\s*=\s*([0-9]+)\s*$", flags=re.MULTILINE) + r"^\s*#\s*sphinx_gallery_thumbnail_number\s*=\s*([0-9]+)\s*$", flags=re.MULTILINE) match = pattr.search(text) if match is None: From e2088cdc49da0d3ee00ffe638934527c5333f274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 22:36:55 +0200 Subject: [PATCH 44/60] Change logic statements of when to execute script --- sphinx_gallery/gen_rst.py | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 3fb58e945..43bbe9f0d 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -469,15 +469,15 @@ def generate_dir_rst(src_dir, target_dir, gallery_conf, seen_backrefs): return fhindex, computation_times -def execute_codeblock(code_block, example_globals, image_path, fig_count, +def execute_codeblock(code_block, example_globals, image_path, src_file, gallery_conf): """Executes the code block of the example file""" time_elapsed = 0 stdout = '' # If the example is marked as failing skip executing its blocks - if src_file in gallery_conf['failing_examples']: - return '', 0, 0 + if example_globals['__example_has_failed__']: + return stdout, time_elapsed # We need to execute the code print('plotting code blocks in %s' % src_file) @@ -486,6 +486,7 @@ def execute_codeblock(code_block, example_globals, image_path, fig_count, cwd = os.getcwd() # Redirect output to stdout and orig_stdout = sys.stdout + fig_count = example_globals['__fig_count__'] try: # First cd in the original example dir, so that any file @@ -539,6 +540,7 @@ def execute_codeblock(code_block, example_globals, image_path, fig_count, raise # Stores failing file gallery_conf['failing_examples'][src_file] = formatted_exception + example_globals['__example_has_failed__'] = True finally: os.chdir(cwd) @@ -546,8 +548,9 @@ def execute_codeblock(code_block, example_globals, image_path, fig_count, print(" - time elapsed : %.2g sec" % time_elapsed) code_output = u"\n{0}\n\n{1}\n\n".format(image_list, stdout) + example_globals['__fig_count__'] += len(figure_list) - return code_output, time_elapsed, fig_count + len(figure_list) + return code_output, time_elapsed def generate_file_rst(fname, target_dir, src_dir, gallery_conf): @@ -594,7 +597,9 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): example_nb = Notebook(fname, target_dir) filename_pattern = gallery_conf.get('filename_pattern') - if re.search(filename_pattern, src_file) and gallery_conf['plot_gallery']: + execute_script = re.search(filename_pattern, src_file) and gallery_conf[ + 'plot_gallery'] + if execute_script: example_globals = { # A lot of examples contains 'print(__doc__)' for example in # scikit-learn so that running the example prints some useful @@ -605,20 +610,22 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): '__doc__': '', # Examples may contain if __name__ == '__main__' guards # for in example scikit-learn if the example uses multiprocessing - '__name__': '__main__'} + '__name__': '__main__', + # Keeps track of generated figures + '__fig_count__': 0, + '__example_has_failed__': not execute_script, + } - fig_count = 0 # A simple example has two blocks: one for the # example introduction/explanation and one for the code is_example_notebook_like = len(script_blocks) > 2 for blabel, bcontent in script_blocks: if blabel == 'code': - code_output, rtime, fig_count = execute_codeblock(bcontent, - example_globals, - image_path_template, - fig_count, - src_file, - gallery_conf) + code_output, rtime = execute_codeblock(bcontent, + example_globals, + image_path_template, + src_file, + gallery_conf) time_elapsed += rtime example_nb.add_code_cell(bcontent) From ef79cce60918600bbf698f46bf33e4987bebc038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 22:53:18 +0200 Subject: [PATCH 45/60] save_figures now returns the rst for images --- sphinx_gallery/gen_rst.py | 36 +++++++++++++++------------- sphinx_gallery/tests/test_gen_rst.py | 4 ++-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 43bbe9f0d..0292c04ed 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -350,7 +350,18 @@ def save_figures(image_path, fig_count, gallery_conf): figure_list.append(current_fig) mlab.close(all=True) - return figure_list + # Depending on whether we have one or more figures, we're using a + # horizontal list or a single rst call to 'image'. + images_rst = "" + if len(figure_list) == 1: + figure_name = figure_list[0] + images_rst = SINGLE_IMAGE % figure_name.lstrip('/') + elif len(figure_list) > 1: + images_rst = HLIST_HEADER + for figure_name in figure_list: + images_rst += HLIST_IMAGE_TEMPLATE % figure_name.lstrip('/') + + return figure_list, images_rst def scale_image(in_fname, out_fname, max_width, max_height): @@ -509,18 +520,9 @@ def execute_codeblock(code_block, example_globals, image_path, if my_stdout: stdout = CODE_OUTPUT.format(indent(my_stdout, u' ' * 4)) os.chdir(cwd) - figure_list = save_figures(image_path, fig_count, gallery_conf) - - # Depending on whether we have one or more figures, we're using a - # horizontal list or a single rst call to 'image'. - image_list = "" - if len(figure_list) == 1: - figure_name = figure_list[0] - image_list = SINGLE_IMAGE % figure_name.lstrip('/') - elif len(figure_list) > 1: - image_list = HLIST_HEADER - for figure_name in figure_list: - image_list += HLIST_IMAGE_TEMPLATE % figure_name.lstrip('/') + fig_list, images_rst = save_figures( + image_path, fig_count, gallery_conf) + fig_num = len(fig_list) except Exception: formatted_exception = traceback.format_exc() @@ -530,8 +532,8 @@ def execute_codeblock(code_block, example_globals, image_path, formatted_exception + 80 * '_' + '\n' warnings.warn(fail_example_warning) - figure_list = [] - image_list = codestr2rst(formatted_exception, lang='pytb') + fig_num = 0 + images_rst = codestr2rst(formatted_exception, lang='pytb') # Breaks build on first example error # XXX This check can break during testing e.g. if you uncomment the @@ -547,8 +549,8 @@ def execute_codeblock(code_block, example_globals, image_path, sys.stdout = orig_stdout print(" - time elapsed : %.2g sec" % time_elapsed) - code_output = u"\n{0}\n\n{1}\n\n".format(image_list, stdout) - example_globals['__fig_count__'] += len(figure_list) + code_output = u"\n{0}\n\n{1}\n\n".format(images_rst, stdout) + example_globals['__fig_count__'] += fig_num return code_output, time_elapsed diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 312302b7e..c9be06863 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -246,14 +246,14 @@ def test_save_figures(): mlab.test_plot3d() plt.plot(1, 1) fname_template = os.path.join(examples_dir, 'image{0}.png') - fig_list = sg.save_figures(fname_template, 0, gallery_conf) + fig_list, _ = sg.save_figures(fname_template, 0, gallery_conf) assert_equal(len(fig_list), 2) assert fig_list[0].endswith('image1.png') assert fig_list[1].endswith('image2.png') mlab.test_plot3d() plt.plot(1, 1) - fig_list = sg.save_figures(fname_template, 2, gallery_conf) + fig_list, _ = sg.save_figures(fname_template, 2, gallery_conf) assert_equal(len(fig_list), 2) assert fig_list[0].endswith('image3.png') assert fig_list[1].endswith('image4.png') From dde4dff00d7192a5fc5fc1a0ce8c99e6ebe9f367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 26 Jun 2016 23:05:26 +0200 Subject: [PATCH 46/60] Simplified logic for generating rst file The loop that writes the rst information of the example script file is unique. The control of weather the script is executed is evaluated in the execute block, not in the rst generator. --- sphinx_gallery/gen_rst.py | 93 ++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 0292c04ed..fa936f60b 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -601,61 +601,52 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): filename_pattern = gallery_conf.get('filename_pattern') execute_script = re.search(filename_pattern, src_file) and gallery_conf[ 'plot_gallery'] - if execute_script: - example_globals = { - # A lot of examples contains 'print(__doc__)' for example in - # scikit-learn so that running the example prints some useful - # information. Because the docstring has been separated from - # the code blocks in sphinx-gallery, __doc__ is actually - # __builtin__.__doc__ in the execution context and we do not - # want to print it - '__doc__': '', - # Examples may contain if __name__ == '__main__' guards - # for in example scikit-learn if the example uses multiprocessing - '__name__': '__main__', - # Keeps track of generated figures - '__fig_count__': 0, - '__example_has_failed__': not execute_script, - } - - # A simple example has two blocks: one for the - # example introduction/explanation and one for the code - is_example_notebook_like = len(script_blocks) > 2 - for blabel, bcontent in script_blocks: - if blabel == 'code': - code_output, rtime = execute_codeblock(bcontent, - example_globals, - image_path_template, - src_file, - gallery_conf) - - time_elapsed += rtime - example_nb.add_code_cell(bcontent) - - if is_example_notebook_like: - example_rst += codestr2rst(bcontent) + '\n' - example_rst += code_output - else: - example_rst += code_output - if 'sphx-glr-script-out' in code_output: - # Add some vertical space after output - example_rst += "\n\n|\n\n" - example_rst += codestr2rst(bcontent) + '\n' - - else: - example_rst += text2string(bcontent) + '\n' - example_nb.add_markdown_cell(text2string(bcontent)) - else: - for blabel, bcontent in script_blocks: - if blabel == 'code': + example_globals = { + # A lot of examples contains 'print(__doc__)' for example in + # scikit-learn so that running the example prints some useful + # information. Because the docstring has been separated from + # the code blocks in sphinx-gallery, __doc__ is actually + # __builtin__.__doc__ in the execution context and we do not + # want to print it + '__doc__': '', + # Examples may contain if __name__ == '__main__' guards + # for in example scikit-learn if the example uses multiprocessing + '__name__': '__main__', + # Keeps track of generated figures + '__fig_count__': 0, + '__example_has_failed__': not execute_script, + } + + # A simple example has two blocks: one for the + # example introduction/explanation and one for the code + is_example_notebook_like = len(script_blocks) > 2 + for blabel, bcontent in script_blocks: + if blabel == 'code': + code_output, rtime = execute_codeblock(bcontent, + example_globals, + image_path_template, + src_file, + gallery_conf) + + time_elapsed += rtime + example_nb.add_code_cell(bcontent) + + if is_example_notebook_like: example_rst += codestr2rst(bcontent) + '\n' - example_nb.add_code_cell(bcontent) + example_rst += code_output else: - example_rst += bcontent + '\n' - example_nb.add_markdown_cell(text2string(bcontent)) + example_rst += code_output + if 'sphx-glr-script-out' in code_output: + # Add some vertical space after output + example_rst += "\n\n|\n\n" + example_rst += codestr2rst(bcontent) + '\n' + + else: + example_rst += text2string(bcontent) + '\n' + example_nb.add_markdown_cell(text2string(bcontent)) # Writes md5 checksum if example has build correctly - if not src_file in gallery_conf['failing_examples']: + if src_file not in gallery_conf['failing_examples']: with open(example_file + '.md5', 'w') as file_checksum: file_checksum.write(get_md5sum(example_file)) From ece117d2f525f079d37e7dc000746a86f0043e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Mon, 27 Jun 2016 00:12:46 +0200 Subject: [PATCH 47/60] save_thumbnail finds image to display --- sphinx_gallery/gen_rst.py | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index fa936f60b..cbbf8db4b 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -409,8 +409,13 @@ def scale_image(in_fname, out_fname, max_width, max_height): generated images') -def save_thumbnail(thumbnail_image_path, src_file, gallery_conf): +def save_thumbnail(image_path_template, src_file, gallery_conf): """Save the thumbnail image""" + # read specification of the figure to display as thumbnail from main text + _, content = get_docstring_and_rest(src_file) + thumbnail_number = extract_thumbnail_number(content) + thumbnail_image_path = image_path_template.format(thumbnail_number) + thumb_dir = os.path.join(os.path.dirname(thumbnail_image_path), 'thumb') if not os.path.exists(thumb_dir): os.makedirs(thumb_dir) @@ -568,8 +573,13 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): """ src_file = os.path.join(src_dir, fname) - example_file = os.path.join(target_dir, fname) - shutil.copyfile(src_file, example_file) + script_blocks = split_code_and_text_blocks(src_file) + amount_of_code = sum([len(bcontent) + for blabel, bcontent in script_blocks + if blabel == 'code']) + + if md5sum_is_current(src_file): + return amount_of_code, 0 image_dir = os.path.join(target_dir, 'images') if not os.path.exists(image_dir): @@ -579,21 +589,8 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): image_fname = 'sphx_glr_' + base_image_name + '_{0:03}.png' image_path_template = os.path.join(image_dir, image_fname) - script_blocks = split_code_and_text_blocks(example_file) - - # read specification of the figure to display as thumbnail from main text - _, content = get_docstring_and_rest(example_file) - thumbnail_number = extract_thumbnail_number(content) - - amount_of_code = sum([len(bcontent) - for blabel, bcontent in script_blocks - if blabel == 'code']) - - if md5sum_is_current(example_file): - return amount_of_code, 0 - - time_elapsed = 0 - + example_file = os.path.join(target_dir, fname) + shutil.copyfile(src_file, example_file) ref_fname = example_file.replace(os.path.sep, '_') example_rst = """\n\n.. _sphx_glr_{0}:\n\n""".format(ref_fname) example_nb = Notebook(fname, target_dir) @@ -620,6 +617,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): # A simple example has two blocks: one for the # example introduction/explanation and one for the code is_example_notebook_like = len(script_blocks) > 2 + time_elapsed = 0 for blabel, bcontent in script_blocks: if blabel == 'code': code_output, rtime = execute_codeblock(bcontent, @@ -650,8 +648,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): with open(example_file + '.md5', 'w') as file_checksum: file_checksum.write(get_md5sum(example_file)) - thumbnail_image_path = image_path_template.format(thumbnail_number) - save_thumbnail(thumbnail_image_path, src_file, gallery_conf) + save_thumbnail(image_path_template, src_file, gallery_conf) time_m, time_s = divmod(time_elapsed, 60) example_nb.save_file() From 76bda4add441a4fd763f397e7fe1b0c62c14b693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 3 Jul 2016 20:31:13 +0200 Subject: [PATCH 48/60] Explicit failed example order --- examples/plot_raise.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/plot_raise.py b/examples/plot_raise.py index db504a83c..8fb6e2c5b 100644 --- a/examples/plot_raise.py +++ b/examples/plot_raise.py @@ -10,14 +10,6 @@ You also get the python traceback of the failed code block """ -iae - -############################################################################### -# Sphinx gallery will stop executing the remaining code blocks after -# the exception has occurred in the example script. Nevertheless the -# html will still render all the example annotated text and -# code blocks, but no output will be shown. - # Code source: Óscar Nájera # License: BSD 3 clause @@ -26,8 +18,18 @@ plt.pcolormesh(np.random.randn(100, 100)) +############################################################################### +# This next block will raise a NameError + +iae + +############################################################################### +# Sphinx gallery will stop executing the remaining code blocks after +# the exception has occurred in the example script. Nevertheless the +# html will still render all the example annotated text and +# code blocks, but no output will be shown. ############################################################################### -# Here is another error raising Block +# Here is another error raising Block but will not be executed plt.plot('Strings are not a valid argument for the plot function') From 04672f2e63e38243b361548d879ccc286e8a37e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 3 Jul 2016 20:43:52 +0200 Subject: [PATCH 49/60] Fig bug: Examples are not rerun on second+ build --- sphinx_gallery/gen_rst.py | 7 +++---- sphinx_gallery/tests/test_gen_rst.py | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index cbbf8db4b..c8e5f0506 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -565,7 +565,6 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): Returns ------- - amount_of_code : int character count of the corresponding python script in file time_elapsed : float @@ -573,12 +572,14 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): """ src_file = os.path.join(src_dir, fname) + example_file = os.path.join(target_dir, fname) + shutil.copyfile(src_file, example_file) script_blocks = split_code_and_text_blocks(src_file) amount_of_code = sum([len(bcontent) for blabel, bcontent in script_blocks if blabel == 'code']) - if md5sum_is_current(src_file): + if md5sum_is_current(example_file): return amount_of_code, 0 image_dir = os.path.join(target_dir, 'images') @@ -589,8 +590,6 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): image_fname = 'sphx_glr_' + base_image_name + '_{0:03}.png' image_path_template = os.path.join(image_dir, image_fname) - example_file = os.path.join(target_dir, fname) - shutil.copyfile(src_file, example_file) ref_fname = example_file.replace(os.path.sep, '_') example_rst = """\n\n.. _sphx_glr_{0}:\n\n""".format(ref_fname) example_nb = Notebook(fname, target_dir) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index c9be06863..01b8b60b7 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -261,3 +261,4 @@ def test_save_figures(): shutil.rmtree(examples_dir) # TODO: test that broken thumbnail does appear when needed +# TODO: test that examples are not executed twice From cbc69e4c05d2650803c355b012ca67676d4202f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 3 Jul 2016 21:32:05 +0200 Subject: [PATCH 50/60] Fix #122 new configuration options `plot_gallery` and `abort_on_example_error` are now configuration variables that can be set in the ``sphinx_gallery_conf`` dictionary in the configuration file. The build option has the highest priority. --- CHANGES.rst | 4 +++- doc/advanced_configuration.rst | 16 ++++++++++++++-- sphinx_gallery/gen_gallery.py | 16 +++++++++++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 21efea469..fb3dccb6f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -15,7 +15,9 @@ New features * Print aggregated and sorted list of computation times of all examples in the console during the build. * For examples that create multiple figures, set the thumbnail image. - +* The ``plot_gallery`` and ``abort_on_example_error`` options can now + be specified in ``sphinx_gallery_conf``. The build option (``-D`` + flag) takes precedence over the ``sphinx_gallery_conf`` option. v0.1.2 ------ diff --git a/doc/advanced_configuration.rst b/doc/advanced_configuration.rst index 7f1ec6bb4..1a3c830a1 100644 --- a/doc/advanced_configuration.rst +++ b/doc/advanced_configuration.rst @@ -251,7 +251,13 @@ your ``Makefile`` with:: @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." Remember that for ``Makefile`` white space is significant and the indentation are tabs -and not spaces +and not spaces. + +Alternatively, you can add the ``plot_gallery`` option to the +``sphinx_gallery_conf`` dictionary inside your ``conf.py`` +configuration file to have it as a default. The highest precedence is +always given to the `-D` flag of the build command. + Dealing with failing Gallery example scripts ============================================ @@ -289,7 +295,13 @@ by including in your ``Makefile``:: @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." Remember that for ``Makefile`` white space is significant and the indentation are tabs -and not spaces +and not spaces. + +Alternatively, you can add the ``abort_on_example_error`` option to +the ``sphinx_gallery_conf`` dictionary inside your ``conf.py`` +configuration file to have it as a default. The highest precedence is +always given to the `-D` flag of the build command. + Don't fail the build on exit ---------------------------- diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 32bdf3a8b..311a5d249 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -194,15 +194,25 @@ def sumarize_failing_examples(app, exception): "\n".join(unexpected_ex_pass)) if fail_msgs: - raise ValueError("Here is a summary of the problems encountered when" + raise ValueError("Here is a summary of the problems encountered when " "running the examples\n\n" + "\n".join(fail_msgs) + "-" * 79) +def get_default_plot_gallery(conf): + return conf['sphinx_gallery_conf'].get('plot_gallery', True) + + +def get_default_abort_on_example(conf): + return conf['sphinx_gallery_conf'].get('abort_on_example_error', False) + + def setup(app): """Setup sphinx-gallery sphinx extension""" - app.add_config_value('plot_gallery', True, 'html') - app.add_config_value('abort_on_example_error', False, 'html') app.add_config_value('sphinx_gallery_conf', DEFAULT_GALLERY_CONF, 'html') + app.add_config_value('plot_gallery', get_default_plot_gallery, 'html') + app.add_config_value('abort_on_example_error', + get_default_abort_on_example, 'html') + app.add_stylesheet('gallery.css') if 'sphinx.ext.autodoc' in app._extensions: From 1c3d19ca0b55a6c40f1a51a56feefa60a055ee35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 3 Jul 2016 21:52:48 +0200 Subject: [PATCH 51/60] Fix text style comments --- CHANGES.rst | 5 +++-- doc/advanced_configuration.rst | 4 ++-- examples/plot_raise.py | 2 +- sphinx_gallery/gen_gallery.py | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index fb3dccb6f..6f4aab62d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,7 @@ New features '''''''''''' * Summary of failing examples with traceback at the end of the sphinx build. By default the build exits with a 1 exit code if an example - has failed. A list of of examples that are expected to fail can be + has failed. A list of examples that are expected to fail can be defined in `conf.py` and exit the build with 0 exitcode. Alternatively it is possible to exit the build as soon as one example has failed. @@ -17,7 +17,8 @@ New features * For examples that create multiple figures, set the thumbnail image. * The ``plot_gallery`` and ``abort_on_example_error`` options can now be specified in ``sphinx_gallery_conf``. The build option (``-D`` - flag) takes precedence over the ``sphinx_gallery_conf`` option. + flag passed to ``sphinx-build``) takes precedence over the + ``sphinx_gallery_conf`` option. v0.1.2 ------ diff --git a/doc/advanced_configuration.rst b/doc/advanced_configuration.rst index 1a3c830a1..fc0199268 100644 --- a/doc/advanced_configuration.rst +++ b/doc/advanced_configuration.rst @@ -256,7 +256,7 @@ and not spaces. Alternatively, you can add the ``plot_gallery`` option to the ``sphinx_gallery_conf`` dictionary inside your ``conf.py`` configuration file to have it as a default. The highest precedence is -always given to the `-D` flag of the build command. +always given to the `-D` flag of the ``sphinx-build`` command. Dealing with failing Gallery example scripts @@ -300,7 +300,7 @@ and not spaces. Alternatively, you can add the ``abort_on_example_error`` option to the ``sphinx_gallery_conf`` dictionary inside your ``conf.py`` configuration file to have it as a default. The highest precedence is -always given to the `-D` flag of the build command. +always given to the `-D` flag of the ``sphinx-build`` command. Don't fail the build on exit diff --git a/examples/plot_raise.py b/examples/plot_raise.py index 8fb6e2c5b..24e0152d6 100644 --- a/examples/plot_raise.py +++ b/examples/plot_raise.py @@ -30,6 +30,6 @@ # code blocks, but no output will be shown. ############################################################################### -# Here is another error raising Block but will not be executed +# Here is another error raising block but will not be executed plt.plot('Strings are not a valid argument for the plot function') diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 311a5d249..247850c60 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -195,7 +195,8 @@ def sumarize_failing_examples(app, exception): if fail_msgs: raise ValueError("Here is a summary of the problems encountered when " - "running the examples\n\n" + "\n".join(fail_msgs) + "-" * 79) + "running the examples\n\n" + "\n".join(fail_msgs) + + "\n" + "-" * 79) def get_default_plot_gallery(conf): From 9857e9490d70f9ae69dd4d9bc7bb542873c76406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 10 Jul 2016 19:12:15 +0200 Subject: [PATCH 52/60] Rename the control variable to run examples Because of the need to stop running examples after they fail and to simplify the control flow logic on when to parse the file only. All were joined in a execution global private variable __example_has_failed__. Now this is renamed to __sphx_glr_run_example__ to better fit the reading of the code. --- sphinx_gallery/gen_rst.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index c8e5f0506..e37bf3e18 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -491,8 +491,8 @@ def execute_codeblock(code_block, example_globals, image_path, time_elapsed = 0 stdout = '' - # If the example is marked as failing skip executing its blocks - if example_globals['__example_has_failed__']: + # If example is not suitable to run, skip executing its blocks + if not example_globals['__sphx_glr_run_example__']: return stdout, time_elapsed # We need to execute the code @@ -547,7 +547,7 @@ def execute_codeblock(code_block, example_globals, image_path, raise # Stores failing file gallery_conf['failing_examples'][src_file] = formatted_exception - example_globals['__example_has_failed__'] = True + example_globals['__sphx_glr_run_example__'] = False finally: os.chdir(cwd) @@ -610,7 +610,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): '__name__': '__main__', # Keeps track of generated figures '__fig_count__': 0, - '__example_has_failed__': not execute_script, + '__sphx_glr_run_example__': execute_script, } # A simple example has two blocks: one for the From 095031d64e11674ae8658da78cc985fa8ffaf385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 10 Jul 2016 19:18:36 +0200 Subject: [PATCH 53/60] [CI] Include a no-plot run This is because this type of run shall succeed regardless of how examples are coded and if they generate errors and even for the case for known failing examples which are accepted to fail and here they shall not manifest themselves. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 943cfde58..7bbd6fe9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,4 +56,7 @@ script: - if [ "$DISTRIB" == "ubuntu" ]; then python setup.py nosetests; fi - if [ "$DISTRIB" == "conda" ]; then nosetests; fi - cd doc + # Test a fast run of no-plot - make html + # Test the full run + - make html-noplot From 2fb0cc607e9fa9f15f81c650720306269efcf790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 10 Jul 2016 19:25:58 +0200 Subject: [PATCH 54/60] [Fix BUG] no-plot caches the md5sum files If running under no-plot all files are generated correctly and no example is assumed to fail. Thus md5sum files where written and on next builds of the project no example would be executed to generate the images. TODO test reminder added --- sphinx_gallery/gen_rst.py | 3 ++- sphinx_gallery/tests/test_gen_rst.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index e37bf3e18..0cfff4be0 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -643,7 +643,8 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): example_nb.add_markdown_cell(text2string(bcontent)) # Writes md5 checksum if example has build correctly - if src_file not in gallery_conf['failing_examples']: + # not failed and was initially meant to run(no-plot shall not cache md5sum) + if src_file not in gallery_conf['failing_examples'] and execute_script: with open(example_file + '.md5', 'w') as file_checksum: file_checksum.write(get_md5sum(example_file)) diff --git a/sphinx_gallery/tests/test_gen_rst.py b/sphinx_gallery/tests/test_gen_rst.py index 01b8b60b7..177bb7cb4 100644 --- a/sphinx_gallery/tests/test_gen_rst.py +++ b/sphinx_gallery/tests/test_gen_rst.py @@ -262,3 +262,5 @@ def test_save_figures(): # TODO: test that broken thumbnail does appear when needed # TODO: test that examples are not executed twice +# TODO: test that examples are executed after a no-plot and produce +# the correct image in the thumbnail From d02b4e09ed4fc6207792e45519261e9131650dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 10 Jul 2016 19:36:40 +0200 Subject: [PATCH 55/60] Don't execute example fail summary on no-plot --- sphinx_gallery/gen_gallery.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 247850c60..8ca80001c 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -15,7 +15,6 @@ import copy import re import os -import warnings from . import glr_path_static from .gen_rst import generate_dir_rst, SPHX_GLR_SIG from .docs_resolv import embed_code_links @@ -165,6 +164,10 @@ def sumarize_failing_examples(app, exception): if exception is not None: return + # Under no-plot execution it failing examples play no role + if not app.config.sphinx_gallery_conf['plot_gallery']: + return + gallery_conf = app.config.sphinx_gallery_conf failing_examples = set(gallery_conf['failing_examples']) expected_failing_examples = set(gallery_conf['expected_failing_examples']) From 637e57fcd6bbe49440f8cd9431a95e124fee8883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Sun, 10 Jul 2016 19:51:48 +0200 Subject: [PATCH 56/60] Simplify control logic on write md5sum file --- sphinx_gallery/gen_rst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 0cfff4be0..1c3f4eb59 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -644,7 +644,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): # Writes md5 checksum if example has build correctly # not failed and was initially meant to run(no-plot shall not cache md5sum) - if src_file not in gallery_conf['failing_examples'] and execute_script: + if example_globals['__sphx_glr_run_example__']: with open(example_file + '.md5', 'w') as file_checksum: file_checksum.write(get_md5sum(example_file)) From f66eeddf1365a44e854dccd857f33718b6bb8432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Jul 2016 13:02:21 +0200 Subject: [PATCH 57/60] Address comments --- .travis.yml | 4 +--- CHANGES.rst | 2 +- sphinx_gallery/gen_gallery.py | 5 ++++- sphinx_gallery/gen_rst.py | 11 ++++++++--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7bbd6fe9b..a1b0a30a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,5 @@ script: - if [ "$DISTRIB" == "ubuntu" ]; then python setup.py nosetests; fi - if [ "$DISTRIB" == "conda" ]; then nosetests; fi - cd doc - # Test a fast run of no-plot - - make html - # Test the full run - make html-noplot + - make html diff --git a/CHANGES.rst b/CHANGES.rst index 6f4aab62d..1b7b378c6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,7 +10,7 @@ New features build. By default the build exits with a 1 exit code if an example has failed. A list of examples that are expected to fail can be defined in `conf.py` and exit the build with 0 - exitcode. Alternatively it is possible to exit the build as soon as + exit code. Alternatively it is possible to exit the build as soon as one example has failed. * Print aggregated and sorted list of computation times of all examples in the console during the build. diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 8ca80001c..d2a1f316c 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -160,7 +160,10 @@ def touch_empty_backreferences(app, what, name, obj, options, lines): def sumarize_failing_examples(app, exception): - """Embed hyperlinks to documentation into example code""" + """Collects the list of falling examples during build and prints them with the traceback + + Raises ValueError if there where failing examples +""" if exception is not None: return diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 1c3f4eb59..f74c92c84 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -296,8 +296,8 @@ def md5sum_is_current(src_file): if os.path.exists(src_md5_file): with open(src_md5_file, 'r') as file_checksum: ref_md5 = file_checksum.read() - if src_md5 == ref_md5: - return True + + return src_md5 == ref_md5 return False @@ -311,10 +311,15 @@ def save_figures(image_path, fig_count, gallery_conf): Path where plots are saved (format string which accepts figure number) fig_count : int Previous figure number count. Figure number add from this number + gallery_conf : dict + Contains the configuration of Sphinx-Gallery Returns ------- - list of strings containing the full path to each figure + figure_list : list of str + strings containing the full path to each figure + images_rst : str + rst code to embed the images in the document """ figure_list = [] From 31c0dfa114a1f1732019afa618a0d3ed938ab805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Jul 2016 17:53:01 +0200 Subject: [PATCH 58/60] Address comments --- sphinx_gallery/gen_gallery.py | 23 ++++++++++------------- sphinx_gallery/gen_rst.py | 14 +++++++------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index d2a1f316c..e96649695 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -163,11 +163,11 @@ def sumarize_failing_examples(app, exception): """Collects the list of falling examples during build and prints them with the traceback Raises ValueError if there where failing examples -""" + """ if exception is not None: return - # Under no-plot execution it failing examples play no role + # Under no-plot Examples are not run so nothing to summarize if not app.config.sphinx_gallery_conf['plot_gallery']: return @@ -179,7 +179,7 @@ def sumarize_failing_examples(app, exception): expected_failing_examples) expected_fail_msg = [] if still_failing_examples: - expected_fail_msg.append("Known failing examples, still failing:") + expected_fail_msg.append("Examples failing as expected:") for fail_example in still_failing_examples: expected_fail_msg.append(fail_example + ' failed leaving traceback:\n' + gallery_conf['failing_examples'][fail_example] + '\n') @@ -196,7 +196,7 @@ def sumarize_failing_examples(app, exception): unexpected_ex_pass = expected_failing_examples.difference(failing_examples) if unexpected_ex_pass: - fail_msgs.append("Examples that are not failing anymore:\n" + + fail_msgs.append("Examples expected to fail, but not failling:\n" + "\n".join(unexpected_ex_pass)) if fail_msgs: @@ -205,20 +205,17 @@ def sumarize_failing_examples(app, exception): "\n" + "-" * 79) -def get_default_plot_gallery(conf): - return conf['sphinx_gallery_conf'].get('plot_gallery', True) - - -def get_default_abort_on_example(conf): - return conf['sphinx_gallery_conf'].get('abort_on_example_error', False) +def get_default_config_value(key): + def default_getter(conf): + return conf['sphinx_gallery_conf'].get(key, DEFAULT_GALLERY_CONF[key]) + return default_getter def setup(app): """Setup sphinx-gallery sphinx extension""" app.add_config_value('sphinx_gallery_conf', DEFAULT_GALLERY_CONF, 'html') - app.add_config_value('plot_gallery', get_default_plot_gallery, 'html') - app.add_config_value('abort_on_example_error', - get_default_abort_on_example, 'html') + for key in ['plot_gallery', 'abort_on_example_error']: + app.add_config_value(key, get_default_config_value(key), 'html') app.add_stylesheet('gallery.css') diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index f74c92c84..12d3efbd3 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -490,8 +490,8 @@ def generate_dir_rst(src_dir, target_dir, gallery_conf, seen_backrefs): return fhindex, computation_times -def execute_codeblock(code_block, example_globals, image_path, - src_file, gallery_conf): +def execute_code_block(code_block, example_globals, image_path, + src_file, gallery_conf): """Executes the code block of the example file""" time_elapsed = 0 stdout = '' @@ -624,11 +624,11 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): time_elapsed = 0 for blabel, bcontent in script_blocks: if blabel == 'code': - code_output, rtime = execute_codeblock(bcontent, - example_globals, - image_path_template, - src_file, - gallery_conf) + code_output, rtime = execute_code_block(bcontent, + example_globals, + image_path_template, + src_file, + gallery_conf) time_elapsed += rtime example_nb.add_code_cell(bcontent) From e0d90bd1d165dcc3a71ee7f22c2d74207cf79282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Thu, 21 Jul 2016 18:01:56 +0200 Subject: [PATCH 59/60] Pass block execution variables as a dictionary Stop using multiple variables or the script example globals which should remain the globals namespace of the running example --- sphinx_gallery/gen_rst.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index 12d3efbd3..738566229 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -490,24 +490,21 @@ def generate_dir_rst(src_dir, target_dir, gallery_conf, seen_backrefs): return fhindex, computation_times -def execute_code_block(code_block, example_globals, image_path, - src_file, gallery_conf): +def execute_code_block(code_block, example_globals, + block_vars, gallery_conf): """Executes the code block of the example file""" time_elapsed = 0 stdout = '' # If example is not suitable to run, skip executing its blocks - if not example_globals['__sphx_glr_run_example__']: + if not block_vars['execute_script']: return stdout, time_elapsed - # We need to execute the code - print('plotting code blocks in %s' % src_file) - plt.close('all') cwd = os.getcwd() # Redirect output to stdout and orig_stdout = sys.stdout - fig_count = example_globals['__fig_count__'] + src_file = block_vars['src_file'] try: # First cd in the original example dir, so that any file @@ -531,7 +528,7 @@ def execute_code_block(code_block, example_globals, image_path, stdout = CODE_OUTPUT.format(indent(my_stdout, u' ' * 4)) os.chdir(cwd) fig_list, images_rst = save_figures( - image_path, fig_count, gallery_conf) + block_vars['image_path'], block_vars['fig_count'], gallery_conf) fig_num = len(fig_list) except Exception: @@ -552,7 +549,7 @@ def execute_code_block(code_block, example_globals, image_path, raise # Stores failing file gallery_conf['failing_examples'][src_file] = formatted_exception - example_globals['__sphx_glr_run_example__'] = False + block_vars['execute_script'] = False finally: os.chdir(cwd) @@ -560,7 +557,7 @@ def execute_code_block(code_block, example_globals, image_path, print(" - time elapsed : %.2g sec" % time_elapsed) code_output = u"\n{0}\n\n{1}\n\n".format(images_rst, stdout) - example_globals['__fig_count__'] += fig_num + block_vars['fig_count'] += fig_num return code_output, time_elapsed @@ -613,21 +610,19 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): # Examples may contain if __name__ == '__main__' guards # for in example scikit-learn if the example uses multiprocessing '__name__': '__main__', - # Keeps track of generated figures - '__fig_count__': 0, - '__sphx_glr_run_example__': execute_script, } # A simple example has two blocks: one for the # example introduction/explanation and one for the code is_example_notebook_like = len(script_blocks) > 2 time_elapsed = 0 + block_vars = {'execute_script': execute_script, 'fig_count': 0, + 'image_path': image_path_template, 'src_file': src_file} for blabel, bcontent in script_blocks: if blabel == 'code': code_output, rtime = execute_code_block(bcontent, example_globals, - image_path_template, - src_file, + block_vars, gallery_conf) time_elapsed += rtime @@ -649,7 +644,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf): # Writes md5 checksum if example has build correctly # not failed and was initially meant to run(no-plot shall not cache md5sum) - if example_globals['__sphx_glr_run_example__']: + if block_vars['execute_script']: with open(example_file + '.md5', 'w') as file_checksum: file_checksum.write(get_md5sum(example_file)) From 16da3e65f80b9716f743b7a48c12e68b44418a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20N=C3=A1jera?= Date: Fri, 22 Jul 2016 11:26:51 +0200 Subject: [PATCH 60/60] Harmonize example_fail vars for summary function More explicit message for examples not failing anymore --- sphinx_gallery/gen_gallery.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index e96649695..7e593819d 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -175,29 +175,33 @@ def sumarize_failing_examples(app, exception): failing_examples = set(gallery_conf['failing_examples']) expected_failing_examples = set(gallery_conf['expected_failing_examples']) - still_failing_examples = failing_examples.intersection( + examples_expected_to_fail = failing_examples.intersection( expected_failing_examples) expected_fail_msg = [] - if still_failing_examples: + if examples_expected_to_fail: expected_fail_msg.append("Examples failing as expected:") - for fail_example in still_failing_examples: + for fail_example in examples_expected_to_fail: expected_fail_msg.append(fail_example + ' failed leaving traceback:\n' + gallery_conf['failing_examples'][fail_example] + '\n') print("\n".join(expected_fail_msg)) - unexpected_ex_fails = failing_examples.difference( + examples_not_expected_to_fail = failing_examples.difference( expected_failing_examples) fail_msgs = [] - if unexpected_ex_fails: + if examples_not_expected_to_fail: fail_msgs.append("Unexpected failing examples:") - for fail_example in unexpected_ex_fails: + for fail_example in examples_not_expected_to_fail: fail_msgs.append(fail_example + ' failed leaving traceback:\n' + gallery_conf['failing_examples'][fail_example] + '\n') - unexpected_ex_pass = expected_failing_examples.difference(failing_examples) - if unexpected_ex_pass: + examples_not_expected_to_pass = expected_failing_examples.difference( + failing_examples) + if examples_not_expected_to_pass: fail_msgs.append("Examples expected to fail, but not failling:\n" + - "\n".join(unexpected_ex_pass)) + "Please remove this examples from\n" + + "sphinx_gallery_conf['expected_failing_examples']\n" + + "in your conf.py file" + "\n".join(examples_not_expected_to_pass)) if fail_msgs: raise ValueError("Here is a summary of the problems encountered when "