diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c2002409c1db263e86a184ef005d84d1e8594431..5dd5539ca8218b0277c496802529134daac34e4d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -54,8 +54,6 @@ benchmarks_and_profiling: - tests stage: benchmarks_and_profiling only: -# refs: -# - master variables: - $BENCHMARKS_AND_PROFILING script: diff --git a/benchmarks/benchmark_all_examples.py b/benchmarks/benchmark_all_examples.py index 676bfe16ba94d53682ff6e52d7b714d8fa1c2d8b..5687ad8a2be4ae02fb2f0b14f2c5873fe89e798e 100644 --- a/benchmarks/benchmark_all_examples.py +++ b/benchmarks/benchmark_all_examples.py @@ -9,6 +9,10 @@ import pkg_resources from benchmarker import Benchmarker from importlib_resources import path +from flatland.utils import graphics_pil + +graphics_pil.unattended_switch = True + for entry in [entry for entry in importlib_resources.contents('examples') if not pkg_resources.resource_isdir('examples', entry) and entry.endswith(".py") diff --git a/benchmarks/benchmark_utils.py b/benchmarks/benchmark_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..720590be315ca03abd07838c4475a5c586edf8dd --- /dev/null +++ b/benchmarks/benchmark_utils.py @@ -0,0 +1,35 @@ +import contextlib + + +# Copied from https://docs.python.org/3/library/test.html + +@contextlib.contextmanager +def swap_attr(obj, attr, new_val): + """Temporary swap out an attribute with a new object. + + Usage: + with swap_attr(obj, "attr", 5): + ... + + This will set obj.attr to 5 for the duration of the with: block, + restoring the old value at the end of the block. If `attr` doesn't + exist on `obj`, it will be created and then deleted at the end of the + block. + + The old value (or None if it doesn't exist) will be assigned to the + target of the "as" clause, if there is one. + """ + if hasattr(obj, attr): + real_val = getattr(obj, attr) + setattr(obj, attr, new_val) + try: + yield real_val + finally: + setattr(obj, attr, real_val) + else: + setattr(obj, attr, new_val) + try: + yield + finally: + if hasattr(obj, attr): + delattr(obj, attr) diff --git a/benchmarks/profile_all_examples.py b/benchmarks/profile_all_examples.py index 0b6db571e263567e72dc0f955ce478a9384a02d6..b41f52a8cb9a9d261dcaf656b7aa4a11e8885374 100644 --- a/benchmarks/profile_all_examples.py +++ b/benchmarks/profile_all_examples.py @@ -2,19 +2,17 @@ import cProfile import runpy import sys from io import StringIO -from test.support import swap_attr import importlib_resources import pkg_resources from importlib_resources import path +from benchmarks.benchmark_utils import swap_attr +from flatland.utils import graphics_pil + def profile(resource, entry): with path(resource, entry) as file_in: - # we use the test package, which is meant for internal use by Python only internal and - # Any use of this package outside of Python’s standard library is discouraged as code (..) - # can change or be removed without notice between releases of Python. - # https://docs.python.org/3/library/test.html # TODO remove input() from examples print("*****************************************************************") print("Profiling {}".format(entry)) @@ -27,6 +25,8 @@ def profile(resource, entry): cProfile.run('my_func()', sort='time') +graphics_pil.unattended_switch = True + for entry in [entry for entry in importlib_resources.contents('examples') if not pkg_resources.resource_isdir('examples', entry) and entry.endswith(".py") diff --git a/benchmarks/run_all_examples.py b/benchmarks/run_all_examples.py new file mode 100644 index 0000000000000000000000000000000000000000..972ac68ee862e4e80a342cf4d5133a42b28d3df2 --- /dev/null +++ b/benchmarks/run_all_examples.py @@ -0,0 +1,29 @@ +import runpy +import sys +from io import StringIO + +import importlib_resources +import pkg_resources +from importlib_resources import path + +from benchmarks.benchmark_utils import swap_attr +from flatland.utils import graphics_pil + +graphics_pil.unattended_switch = True + +for entry in [entry for entry in importlib_resources.contents('examples') if + not pkg_resources.resource_isdir('examples', entry) + and entry.endswith(".py") + and '__init__' not in entry + and 'example_basic_elements_test' not in entry + and 'demo.py' not in entry + ]: + with path('examples', entry) as file_in: + print("") + print("") + print("") + print("*****************************************************************") + print("Running {}".format(entry)) + print("*****************************************************************") + with swap_attr(sys, "stdin", StringIO("q")): + runpy.run_path(file_in, run_name="__main__") diff --git a/flatland/utils/graphics_pil.py b/flatland/utils/graphics_pil.py index 2332ecf3f0ba2e9ae244d8e4c4c3ab057652f195..22a5c5f25185dd3957470cf7c33c8d6fafd7cda1 100644 --- a/flatland/utils/graphics_pil.py +++ b/flatland/utils/graphics_pil.py @@ -33,6 +33,9 @@ from flatland.core.grid.rail_env_grid import RailEnvTransitions # noqa: E402 class PILGL(GraphicsLayer): + # hack: in continuous integration, we run multiple + unattended_switch = False + def __init__(self, width, height, jupyter=False): self.yxBase = (0, 0) self.linewidth = 4 @@ -157,9 +160,14 @@ class PILGL(GraphicsLayer): def open_window(self): assert self.window_open is False, "Window is already open!" - # use tk.Toplevel() instead of tk.Tk() - # https://stackoverflow.com/questions/26097811/image-pyimage2-doesnt-exist - self.window_root = tk.Tk() + if self.unattended_switch: + # use tk.Toplevel() instead of tk.Tk() since we run all examples from the same python script + # https://stackoverflow.com/questions/26097811/image-pyimage2-doesnt-exist + tk.Toplevel() + else: + tk.Tk() + + self.window_root = tk.Toplevel() self.window_root.withdraw() self.window = tk.Toplevel(self.window_root) self.window.title("Flatland") diff --git a/tox.ini b/tox.ini index b64a20a8db0e6e3df846a0c05bd1e372f93f9136..6e4223172b83be922ac0fa97f981c6ea4c48c1ea 100644 --- a/tox.ini +++ b/tox.ini @@ -52,6 +52,7 @@ setenv = PYTHONPATH = {toxinidir} passenv = DISPLAY + XAUTHORITY ; HTTP_PROXY+HTTPS_PROXY required behind corporate proxies HTTP_PROXY HTTPS_PROXY @@ -68,6 +69,7 @@ setenv = PYTHONPATH = {toxinidir} passenv = DISPLAY + XAUTHORITY ; HTTP_PROXY+HTTPS_PROXY required behind corporate proxies HTTP_PROXY HTTPS_PROXY @@ -94,8 +96,7 @@ deps = commands = ; run examples from subfolder to ensure that resources are accessed via resources and not via relative paths sh -c 'mkdir -p {envtmpdir}/c236d3c240d61a0969d4cb59e2180ce5' -; pipe echo into python since some examples expect input to close the window after the example is run - sh -c 'cd {envtmpdir}/c236d3c240d61a0969d4cb59e2180ce5 && ls {toxinidir}/examples/*.py | xargs -I{} -n 1 sh -c "echo -e \"\n====== Running {} ========\n\"; echo "q" | python {}"' + sh -c 'cd {envtmpdir}/c236d3c240d61a0969d4cb59e2180ce5 && python {toxinidir}/benchmarks/run_all_examples.py' [testenv:notebooks] basepython = python