From 616d27eba33dcb6268ae443e3880300cc82fdc48 Mon Sep 17 00:00:00 2001 From: Seth Troisi Date: Fri, 24 Jan 2020 13:59:16 -0800 Subject: DEV: Use contextmanager in _run_doctests --- tools/refguide_check.py | 82 +++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 43 deletions(-) (limited to 'tools/refguide_check.py') diff --git a/tools/refguide_check.py b/tools/refguide_check.py index ad3f93c42..ecd4a3a2b 100644 --- a/tools/refguide_check.py +++ b/tools/refguide_check.py @@ -25,21 +25,23 @@ or in RST-based documentations:: $ python refguide_check.py --rst docs """ -import sys -import os -import re import copy -import inspect -import warnings import doctest -import tempfile +import glob +import inspect import io -import docutils.core -from docutils.parsers.rst import directives +import os +import re import shutil -import glob -from doctest import NORMALIZE_WHITESPACE, ELLIPSIS, IGNORE_EXCEPTION_DETAIL +import sys +import tempfile +import warnings +import docutils.core from argparse import ArgumentParser +from contextlib import redirect_stderr +from doctest import NORMALIZE_WHITESPACE, ELLIPSIS, IGNORE_EXCEPTION_DETAIL + +from docutils.parsers.rst import directives from pkg_resources import parse_version import sphinx @@ -812,39 +814,33 @@ def _run_doctests(tests, full_name, verbose, doctest_warnings): sys.stdout.flush() # Run tests, trying to restore global state afterward - old_printoptions = np.get_printoptions() - old_errstate = np.seterr() - old_stderr = sys.stderr - cwd = os.getcwd() - tmpdir = tempfile.mkdtemp() - sys.stderr = MyStderr() - try: - os.chdir(tmpdir) - - # try to ensure random seed is NOT reproducible - np.random.seed(None) - - ns = {} - for t in tests: - # We broke the tests up into chunks to try to avoid PSEUDOCODE - # This has the unfortunate side effect of restarting the global - # namespace for each test chunk, so variables will be "lost" after - # a chunk. Chain the globals to avoid this - t.globs.update(ns) - t.filename = short_path(t.filename, cwd) - # Process our options - if any([SKIPBLOCK in ex.options for ex in t.examples]): - continue - fails, successes = runner.run(t, out=out, clear_globs=False) - if fails > 0: - success = False - ns = t.globs - finally: - sys.stderr = old_stderr - os.chdir(cwd) - shutil.rmtree(tmpdir) - np.set_printoptions(**old_printoptions) - np.seterr(**old_errstate) + with np.errstate(), np.printoptions(), redirect_stderr(MyStderr()): + cwd = os.getcwd() + tmpdir = tempfile.mkdtemp() + try: + os.chdir(tmpdir) + + # try to ensure random seed is NOT reproducible + np.random.seed(None) + + ns = {} + for t in tests: + # We broke the tests up into chunks to try to avoid PSEUDOCODE + # This has the unfortunate side effect of restarting the global + # namespace for each test chunk, so variables will be "lost" after + # a chunk. Chain the globals to avoid this + t.globs.update(ns) + t.filename = short_path(t.filename, cwd) + # Process our options + if any([SKIPBLOCK in ex.options for ex in t.examples]): + continue + fails, successes = runner.run(t, out=out, clear_globs=False) + if fails > 0: + success = False + ns = t.globs + finally: + os.chdir(cwd) + shutil.rmtree(tmpdir) return success, output -- cgit v1.2.1 From a71e8a82e38f7bf0668fdf521b1ba47a14a3f628 Mon Sep 17 00:00:00 2001 From: Seth Troisi Date: Fri, 24 Jan 2020 15:01:25 -0800 Subject: DEV: More contextmanager in _run_doctests --- tools/refguide_check.py | 76 +++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 43 deletions(-) (limited to 'tools/refguide_check.py') diff --git a/tools/refguide_check.py b/tools/refguide_check.py index ecd4a3a2b..28bb3ca30 100644 --- a/tools/refguide_check.py +++ b/tools/refguide_check.py @@ -38,7 +38,7 @@ import tempfile import warnings import docutils.core from argparse import ArgumentParser -from contextlib import redirect_stderr +from contextlib import contextmanager, redirect_stderr from doctest import NORMALIZE_WHITESPACE, ELLIPSIS, IGNORE_EXCEPTION_DETAIL from docutils.parsers.rst import directives @@ -792,57 +792,47 @@ def _run_doctests(tests, full_name, verbose, doctest_warnings): runner = DTRunner(full_name, checker=Checker(), optionflags=flags, verbose=verbose) - output = [] + output = io.StringIO(newline='') success = True - def out(msg): - output.append(msg) - - class MyStderr: - """ - Redirect stderr to the current stdout - """ - def write(self, msg): - if doctest_warnings: - sys.stdout.write(msg) - else: - out(msg) - # a flush method is required when a doctest uses multiprocessing - # multiprocessing/popen_fork.py flushes sys.stderr - def flush(self): - if doctest_warnings: - sys.stdout.flush() + # Redirect stderr to the stdout or output + tmp_stderr = sys.stdout if doctest_warnings else output - # Run tests, trying to restore global state afterward - with np.errstate(), np.printoptions(), redirect_stderr(MyStderr()): + @contextmanager + def temp_cwd(): cwd = os.getcwd() tmpdir = tempfile.mkdtemp() try: os.chdir(tmpdir) - - # try to ensure random seed is NOT reproducible - np.random.seed(None) - - ns = {} - for t in tests: - # We broke the tests up into chunks to try to avoid PSEUDOCODE - # This has the unfortunate side effect of restarting the global - # namespace for each test chunk, so variables will be "lost" after - # a chunk. Chain the globals to avoid this - t.globs.update(ns) - t.filename = short_path(t.filename, cwd) - # Process our options - if any([SKIPBLOCK in ex.options for ex in t.examples]): - continue - fails, successes = runner.run(t, out=out, clear_globs=False) - if fails > 0: - success = False - ns = t.globs + yield tmpdir finally: os.chdir(cwd) shutil.rmtree(tmpdir) - return success, output + # Run tests, trying to restore global state afterward + cwd = os.getcwd() + with np.errstate(), np.printoptions(), temp_cwd() as tmpdir, \ + redirect_stderr(tmp_stderr): + # try to ensure random seed is NOT reproducible + np.random.seed(None) + + ns = {} + for t in tests: + # We broke the tests up into chunks to try to avoid PSEUDOCODE + # This has the unfortunate side effect of restarting the global + # namespace for each test chunk, so variables will be "lost" after + # a chunk. Chain the globals to avoid this + t.globs.update(ns) + t.filename = short_path(t.filename, cwd) + # Process our options + if any([SKIPBLOCK in ex.options for ex in t.examples]): + continue + fails, successes = runner.run(t, out=output.write, clear_globs=False) + if fails > 0: + success = False + ns = t.globs + + return success, output.read() def check_doctests(module, verbose, ns=None, @@ -904,7 +894,7 @@ def check_doctests(module, verbose, ns=None, if dots: output_dot('.' if success else 'F') - results.append((full_name, success, "".join(output))) + results.append((full_name, success, output)) if HAVE_MATPLOTLIB: import matplotlib.pyplot as plt @@ -1016,7 +1006,7 @@ def check_doctests_testfile(fname, verbose, ns=None, if dots: output_dot('.' if success else 'F') - results.append((full_name, success, "".join(output))) + results.append((full_name, success, output)) if HAVE_MATPLOTLIB: import matplotlib.pyplot as plt -- cgit v1.2.1