def test_save_matplotlib_figures(gallery_conf, ext): """Test matplotlib figure save""" if ext == 'svg': gallery_conf['image_scrapers'] = (matplotlib_svg_scraper(),) import matplotlib.pyplot as plt # nest these so that Agg can be set plt.plot(1, 1) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('',) * 3 block_vars = dict(image_path_iterator=image_path_iterator) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 1 fname = '/image1.{0}'.format(ext) assert fname in image_rst fname = gallery_conf['gallery_dir'] + fname assert os.path.isfile(fname) # Test capturing 2 images with shifted start number image_path_iterator.next() image_path_iterator.next() plt.plot(1, 1) plt.figure() plt.plot(1, 1) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 5 for ii in range(4, 6): fname = '/image{0}.{1}'.format(ii, ext) assert fname in image_rst fname = gallery_conf['gallery_dir'] + fname assert os.path.isfile(fname)
def test_save_matplotlib_figures(gallery_conf, ext, req_mpl, req_pil): """Test matplotlib figure save.""" if ext == 'svg': gallery_conf['image_scrapers'] = (matplotlib_svg_scraper(),) import matplotlib.pyplot as plt # nest these so that Agg can be set plt.plot(1, 1) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('',) * 3 block_vars = dict(image_path_iterator=image_path_iterator) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 1 fname = '/image1.{0}'.format(ext) assert fname in image_rst fname = gallery_conf['gallery_dir'] + fname assert os.path.isfile(fname) # Test capturing 2 images with shifted start number image_path_iterator.next() image_path_iterator.next() plt.plot(1, 1) plt.figure() plt.plot(1, 1) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 5 for ii in range(4, 6): fname = '/image{0}.{1}'.format(ii, ext) assert fname in image_rst fname = gallery_conf['gallery_dir'] + fname assert os.path.isfile(fname)
def test_save_mayavi_figures(gallery_conf, req_mpl, req_pil): """Test file naming when saving figures. Requires mayavi.""" Image = _get_image() try: from mayavi import mlab except ImportError: raise pytest.skip('Mayavi not installed') import matplotlib.pyplot as plt mlab.options.offscreen = True gallery_conf.update( image_scrapers=(matplotlib_scraper, mayavi_scraper)) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('',) * 3 block_vars = dict(image_path_iterator=image_path_iterator) plt.axes([-0.1, -0.1, 1.2, 1.2]) plt.pcolor([[0]], cmap='Greens') mlab.test_plot3d() image_rst = save_figures(block, block_vars, gallery_conf) assert len(plt.get_fignums()) == 0 assert len(image_path_iterator) == 2 assert '/image0.png' not in image_rst assert '/image1.png' in image_rst assert '/image2.png' in image_rst assert '/image3.png' not in image_rst assert not os.path.isfile(fname_template.format(0)) assert os.path.isfile(fname_template.format(1)) assert os.path.isfile(fname_template.format(2)) assert not os.path.isfile(fname_template.format(0)) with Image.open(fname_template.format(1)) as img: pixels = np.asarray(img.convert("RGB")) assert (pixels == [247, 252, 245]).all() # plt first # Test next-value handling, plus image_scrapers modification gallery_conf.update(image_scrapers=(matplotlib_scraper,)) mlab.test_plot3d() plt.axes([-0.1, -0.1, 1.2, 1.2]) plt.pcolor([[0]], cmap='Reds') image_rst = save_figures(block, block_vars, gallery_conf) assert len(plt.get_fignums()) == 0 assert len(image_path_iterator) == 3 assert '/image1.png' not in image_rst assert '/image2.png' not in image_rst assert '/image3.png' in image_rst assert '/image4.png' not in image_rst assert not os.path.isfile(fname_template.format(0)) for ii in range(3): assert os.path.isfile(fname_template.format(ii + 1)) assert not os.path.isfile(fname_template.format(4)) with Image.open(fname_template.format(3)) as img: pixels = np.asarray(img.convert("RGB")) assert (pixels == [255, 245, 240]).all()
def test_custom_scraper(gallery_conf, monkeypatch): """Test custom scrapers.""" # Test the API contract for custom scrapers complete_args = (gallery_conf, gallery_conf['gallery_dir'], True, False) with monkeypatch.context() as m: m.setattr(sphinx_gallery, '_get_sg_image_scraper', lambda: _custom_func, raising=False) for cust in (_custom_func, 'sphinx_gallery'): gallery_conf.update(image_scrapers=[cust]) # smoke test that it works _complete_gallery_conf(*complete_args, check_keys=False) # degenerate # without the monkey patch to add sphinx_gallery._get_sg_image_scraper, # we should get an error gallery_conf.update(image_scrapers=['sphinx_gallery']) with pytest.raises(ConfigError, match="has no attribute '_get_sg_image_scraper'"): _complete_gallery_conf(*complete_args, check_keys=False) # other degenerate conditions gallery_conf.update(image_scrapers=['foo']) with pytest.raises(ConfigError, match='Unknown image scraper'): _complete_gallery_conf(*complete_args, check_keys=False) gallery_conf.update(image_scrapers=[_custom_func]) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('', ) * 3 block_vars = dict(image_path_iterator=image_path_iterator) with pytest.raises(ExtensionError, match='did not produce expected image'): save_figures(block, block_vars, gallery_conf) gallery_conf.update(image_scrapers=[lambda x, y, z: 1.]) with pytest.raises(ExtensionError, match='was not a string'): save_figures(block, block_vars, gallery_conf) # degenerate string interface gallery_conf.update(image_scrapers=['sphinx_gallery']) with monkeypatch.context() as m: m.setattr(sphinx_gallery, '_get_sg_image_scraper', 'foo', raising=False) with pytest.raises(ConfigError, match='^Unknown image.*\n.*callable'): _complete_gallery_conf(*complete_args, check_keys=False) with monkeypatch.context() as m: m.setattr(sphinx_gallery, '_get_sg_image_scraper', lambda: 'foo', raising=False) with pytest.raises(ConfigError, match='^Scraper.*was not callable'): _complete_gallery_conf(*complete_args, check_keys=False)
def test_custom_scraper(gallery_conf, monkeypatch): """Test custom scrapers.""" # custom finders with monkeypatch.context() as m: m.setattr(sphinx_gallery, '_get_sg_image_scraper', lambda: _custom_func, raising=False) for cust in (_custom_func, 'sphinx_gallery'): gallery_conf.update(image_scrapers=[cust]) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('', ) * 3 block_vars = dict(image_path_iterator=image_path_iterator) # degenerate gallery_conf.update(image_scrapers=['foo']) complete_args = (gallery_conf, gallery_conf['gallery_dir'], True, False) with pytest.raises(ValueError, match='Unknown image scraper'): _complete_gallery_conf(*complete_args) gallery_conf.update( image_scrapers=[lambda x, y, z: y['image_path_iterator'].next()]) with pytest.raises(RuntimeError, match='did not produce expected image'): save_figures(block, block_vars, gallery_conf) gallery_conf.update(image_scrapers=[lambda x, y, z: 1.]) with pytest.raises(TypeError, match='was not a string'): save_figures(block, block_vars, gallery_conf) # degenerate string interface gallery_conf.update(image_scrapers=['sphinx_gallery']) with monkeypatch.context() as m: m.setattr(sphinx_gallery, '_get_sg_image_scraper', 'foo', raising=False) with pytest.raises(ValueError, match='^Unknown image.*\n.*callable'): _complete_gallery_conf(*complete_args) with monkeypatch.context() as m: m.setattr(sphinx_gallery, '_get_sg_image_scraper', lambda: 'foo', raising=False) with pytest.raises(ValueError, match='^Scraper.*was not callable'): _complete_gallery_conf(*complete_args)
def test_save_matplotlib_figures_hidpi(gallery_conf): """Test matplotlib hidpi figure save.""" ext = 'png' gallery_conf['image_srcset'] = ["2x"] import matplotlib.pyplot as plt # nest these so that Agg can be set plt.plot(1, 1) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('', ) * 3 block_vars = dict(image_path_iterator=image_path_iterator) image_rst = save_figures(block, block_vars, gallery_conf) fname = f'/image1.{ext}' assert fname in image_rst assert f'/image1_2_0x.{ext} 2.0x' in image_rst assert len(image_path_iterator) == 1 fname = gallery_conf['gallery_dir'] + fname fnamehi = gallery_conf['gallery_dir'] + f'/image1_2_0x.{ext}' assert os.path.isfile(fname) assert os.path.isfile(fnamehi) # Test capturing 2 images with shifted start number image_path_iterator.next() image_path_iterator.next() plt.plot(1, 1) plt.figure() plt.plot(1, 1) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 5 for ii in range(4, 6): fname = f'/image{ii}.{ext}' assert fname in image_rst fname = gallery_conf['gallery_dir'] + fname assert os.path.isfile(fname) fname = f'/image{ii}_2_0x.{ext}' assert fname in image_rst fname = gallery_conf['gallery_dir'] + fname assert os.path.isfile(fname)
def test_save_matplotlib_figures(gallery_conf): """Test matplotlib figure save""" import matplotlib.pyplot as plt # nest these so that Agg can be set plt.plot(1, 1) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('',) * 3 block_vars = dict(image_path_iterator=image_path_iterator) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 1 assert '/image1.png' in image_rst # Test capturing 2 images with shifted start number image_path_iterator.next() image_path_iterator.next() plt.plot(1, 1) plt.figure() plt.plot(1, 1) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 5 assert '/image4.png' in image_rst assert '/image5.png' in image_rst
def test_save_mayavi_figures(gallery_conf): """Test file naming when saving figures. Requires mayavi.""" try: from mayavi import mlab except ImportError: raise pytest.skip('Mayavi not installed') import matplotlib.pyplot as plt mlab.options.offscreen = True gallery_conf.update( image_scrapers=(matplotlib_scraper, mayavi_scraper)) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('',) * 3 block_vars = dict(image_path_iterator=image_path_iterator) plt.axes([-0.1, -0.1, 1.2, 1.2]) plt.pcolor([[0]], cmap='Greens') mlab.test_plot3d() image_rst = save_figures(block, block_vars, gallery_conf) assert len(plt.get_fignums()) == 0 assert len(image_path_iterator) == 2 assert '/image0.png' not in image_rst assert '/image1.png' in image_rst assert '/image2.png' in image_rst assert '/image3.png' not in image_rst assert not os.path.isfile(fname_template.format(0)) assert os.path.isfile(fname_template.format(1)) assert os.path.isfile(fname_template.format(2)) assert not os.path.isfile(fname_template.format(0)) with Image.open(fname_template.format(1)) as img: pixels = np.asarray(img.convert("RGB")) assert (pixels == [247, 252, 245]).all() # plt first # Test next-value handling, plus image_scrapers modification gallery_conf.update(image_scrapers=(matplotlib_scraper,)) mlab.test_plot3d() plt.axes([-0.1, -0.1, 1.2, 1.2]) plt.pcolor([[0]], cmap='Reds') image_rst = save_figures(block, block_vars, gallery_conf) assert len(plt.get_fignums()) == 0 assert len(image_path_iterator) == 3 assert '/image1.png' not in image_rst assert '/image2.png' not in image_rst assert '/image3.png' in image_rst assert '/image4.png' not in image_rst assert not os.path.isfile(fname_template.format(0)) for ii in range(3): assert os.path.isfile(fname_template.format(ii + 1)) assert not os.path.isfile(fname_template.format(4)) with Image.open(fname_template.format(3)) as img: pixels = np.asarray(img.convert("RGB")) assert (pixels == [255, 245, 240]).all() # custom finders gallery_conf.update(image_scrapers=[lambda x, y, z: '']) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 3 # degenerate gallery_conf.update(image_scrapers=['foo']) with pytest.raises(ValueError, match='Unknown image scraper'): _complete_gallery_conf( gallery_conf, gallery_conf['gallery_dir'], True, False) gallery_conf.update( image_scrapers=[lambda x, y, z: y['image_path_iterator'].next()]) with pytest.raises(RuntimeError, match='did not produce expected image'): save_figures(block, block_vars, gallery_conf) gallery_conf.update(image_scrapers=[lambda x, y, z: 1.]) with pytest.raises(TypeError, match='was not a string'): save_figures(block, block_vars, gallery_conf)
def test_save_mayavi_figures(gallery_conf): """Test file naming when saving figures. Requires mayavi.""" try: from mayavi import mlab except ImportError: raise pytest.skip('Mayavi not installed') import matplotlib.pyplot as plt mlab.options.offscreen = True gallery_conf.update(image_scrapers=(matplotlib_scraper, mayavi_scraper)) fname_template = os.path.join(gallery_conf['gallery_dir'], 'image{0}.png') image_path_iterator = ImagePathIterator(fname_template) block = ('', ) * 3 block_vars = dict(image_path_iterator=image_path_iterator) plt.axes([-0.1, -0.1, 1.2, 1.2]) plt.pcolor([[0]], cmap='Greens') mlab.test_plot3d() image_rst = save_figures(block, block_vars, gallery_conf) assert len(plt.get_fignums()) == 0 assert len(image_path_iterator) == 2 assert '/image0.png' not in image_rst assert '/image1.png' in image_rst assert '/image2.png' in image_rst assert '/image3.png' not in image_rst assert not os.path.isfile(fname_template.format(0)) assert os.path.isfile(fname_template.format(1)) assert os.path.isfile(fname_template.format(2)) assert not os.path.isfile(fname_template.format(0)) with Image.open(fname_template.format(1)) as img: pixels = np.asarray(img.convert("RGB")) assert (pixels == [247, 252, 245]).all() # plt first # Test next-value handling, plus image_scrapers modification gallery_conf.update(image_scrapers=(matplotlib_scraper, )) mlab.test_plot3d() plt.axes([-0.1, -0.1, 1.2, 1.2]) plt.pcolor([[0]], cmap='Reds') image_rst = save_figures(block, block_vars, gallery_conf) assert len(plt.get_fignums()) == 0 assert len(image_path_iterator) == 3 assert '/image1.png' not in image_rst assert '/image2.png' not in image_rst assert '/image3.png' in image_rst assert '/image4.png' not in image_rst assert not os.path.isfile(fname_template.format(0)) for ii in range(3): assert os.path.isfile(fname_template.format(ii + 1)) assert not os.path.isfile(fname_template.format(4)) with Image.open(fname_template.format(3)) as img: pixels = np.asarray(img.convert("RGB")) assert (pixels == [255, 245, 240]).all() # custom finders gallery_conf.update(image_scrapers=[lambda x, y, z: '']) image_rst = save_figures(block, block_vars, gallery_conf) assert len(image_path_iterator) == 3 # degenerate gallery_conf.update(image_scrapers=['foo']) with pytest.raises(ValueError, match='Unknown image scraper'): _complete_gallery_conf(gallery_conf, gallery_conf['gallery_dir'], True, False) gallery_conf.update( image_scrapers=[lambda x, y, z: y['image_path_iterator'].next()]) with pytest.raises(RuntimeError, match='did not produce expected image'): save_figures(block, block_vars, gallery_conf) gallery_conf.update(image_scrapers=[lambda x, y, z: 1.]) with pytest.raises(TypeError, match='was not a string'): save_figures(block, block_vars, gallery_conf)
def execute_code_block(compiler, block, example_globals, script_vars, gallery_conf): """Executes the code block of the example file""" blabel, bcontent, lineno = block # If example is not suitable to run, skip executing its blocks if not script_vars["execute_script"] or blabel == "text": return "" cwd = os.getcwd() # Redirect output to stdout and orig_stdout, orig_stderr = sys.stdout, sys.stderr src_file = script_vars["src_file"] # First cd in the original example dir, so that any file # created by the example get created in this directory captured_std = StringIO() os.chdir(os.path.dirname(src_file)) sys_path = copy.deepcopy(sys.path) sys.path.append(os.getcwd()) sys.stdout = sys.stderr = LoggingTee(captured_std, logger, src_file) try: dont_inherit = 1 if sys.version_info >= (3, 8): ast_Module = partial(ast.Module, type_ignores=[]) else: ast_Module = ast.Module code_ast = ast_Module([bcontent]) code_ast = compile(bcontent, src_file, "exec", ast.PyCF_ONLY_AST | compiler.flags, dont_inherit) ast.increment_lineno(code_ast, lineno - 1) # capture output if last line is expression is_last_expr = False if len(code_ast.body) and isinstance(code_ast.body[-1], ast.Expr): is_last_expr = True last_val = code_ast.body.pop().value # exec body minus last expression _, mem_body = gen_rst._memory_usage( gen_rst._exec_once(compiler(code_ast, src_file, "exec"), example_globals), gallery_conf, ) # exec last expression, made into assignment body = [ ast.Assign(targets=[ast.Name(id="___", ctx=ast.Store())], value=last_val) ] last_val_ast = ast_Module(body=body) ast.fix_missing_locations(last_val_ast) _, mem_last = gen_rst._memory_usage( gen_rst._exec_once(compiler(last_val_ast, src_file, "exec"), example_globals), gallery_conf, ) # capture the assigned variable ___ = example_globals["___"] mem_max = max(mem_body, mem_last) else: _, mem_max = gen_rst._memory_usage( gen_rst._exec_once(compiler(code_ast, src_file, "exec"), example_globals), gallery_conf, ) script_vars["memory_delta"].append(mem_max) except Exception: sys.stdout.flush() sys.stderr.flush() sys.stdout, sys.stderr = orig_stdout, orig_stderr except_rst = gen_rst.handle_exception(sys.exc_info(), src_file, script_vars, gallery_conf) code_output = u"\n{0}\n\n\n\n".format(except_rst) # still call this even though we won't use the images so that # figures are closed scrapers.save_figures(block, script_vars, gallery_conf) else: sys.stdout.flush() sys.stderr.flush() sys.stdout, orig_stderr = orig_stdout, orig_stderr sys.path = sys_path os.chdir(cwd) last_repr = None repr_meth = None if gallery_conf["capture_repr"] != () and is_last_expr: for meth in gallery_conf["capture_repr"]: try: last_repr = getattr(___, meth)() # for case when last statement is print() if last_repr == "None": repr_meth = None else: repr_meth = meth except Exception: pass else: if isinstance(last_repr, str): break captured_std = captured_std.getvalue().expandtabs() # normal string output if repr_meth in ["__repr__", "__str__"] and last_repr: captured_std = u"{0}\n{1}".format(captured_std, last_repr) if captured_std and not captured_std.isspace(): captured_std = CODE_OUTPUT.format(indent(captured_std, u" " * 4)) else: captured_std = "" images_rst = scrapers.save_figures(block, script_vars, gallery_conf) # give html output its own header if repr_meth == "_repr_html_": captured_html = html_header.format(indent(last_repr, u" " * 8)) else: captured_html = "" code_output = u"\n{0}\n\n{1}\n{2}\n\n".format(images_rst, captured_std, captured_html) finally: os.chdir(cwd) sys.path = sys_path sys.stdout, sys.stderr = orig_stdout, orig_stderr return code_output