From e5de0890b0063cb743af18ae0d6945f10442ffcb Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Sun, 18 Apr 2021 10:28:21 -0400 Subject: [PATCH] Improve console error handling, add console.html tests (#1480) --- .circleci/config.yml | 13 +++-- Makefile | 5 ++ conftest.py | 13 +++-- src/pyodide-py/pyodide/console.py | 21 ++++++-- src/pyodide.js | 3 ++ src/templates/console.html | 66 ++++++++++++++++++++------ src/tests/test_console.py | 79 ++++++++++++++++++++++++++++++- 7 files changed, 168 insertions(+), 32 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f5a183a87..8b8f99ebe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,6 @@ defaults: &defaults environment: - EMSDK_NUM_CORES: 4 EMCC_CORES: 4 - PYODIDE_BASE_URL: https://cdn.jsdelivr.net/pyodide/dev/full/ jobs: lint: @@ -95,9 +94,6 @@ jobs: paths: - . - - run: - name: Prepare CircleCI artifacts - command: PYODIDE_BASE_URL="./" make build/console.html - store_artifacts: path: /root/repo/build/ @@ -136,9 +132,6 @@ jobs: paths: - ./packages/.artifacts - ./build - - run: - name: Prepare CircleCI artifacts - command: PYODIDE_BASE_URL="./" make build/console.html - store_artifacts: path: /root/repo/build/ @@ -239,6 +232,9 @@ jobs: tar cjf pyodide-build-${CIRCLE_TAG}.tar.bz2 pyodide/ ghr -t "${GITHUB_TOKEN}" -u "${CIRCLE_PROJECT_USERNAME}" -r "${CIRCLE_PROJECT_REPONAME}" -c "${CIRCLE_SHA1}" -delete "${CIRCLE_TAG}" ./pyodide-build-${CIRCLE_TAG}.tar.bz2 + - run: + name: Set PYODIDE_BASE_URL + command: PYODIDE_BASE_URL="https://cdn.jsdelivr.net/pyodide/dev/full/" make update_base_url - run: name: Deploy to pyodide-cdn2.iodide.io command: | @@ -258,6 +254,9 @@ jobs: - checkout - attach_workspace: at: . + - run: + name: Set PYODIDE_BASE_URL + command: PYODIDE_BASE_URL="https://cdn.jsdelivr.net/pyodide/dev/full/" make update_base_url - run: name: Install requirements command: | diff --git a/Makefile b/Makefile index 559ea109f..986aac01f 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,11 @@ build/webworker_dev.js: src/webworker.js cp $< $@ sed -i -e 's#{{ PYODIDE_BASE_URL }}#./#g' $@ +update_base_url: \ + build/console.html \ + build/pyodide.js \ + build/webworker.js \ + docs/_build/html/console.html test: all pytest src emsdk/tests packages/*/test* pyodide_build -v diff --git a/conftest.py b/conftest.py index 16c2c7583..b4947e54b 100644 --- a/conftest.py +++ b/conftest.py @@ -109,6 +109,14 @@ class SeleniumWrapper: f"{(build_dir / 'test.html').resolve()} " f"does not exist!" ) self.driver.get(f"http://{server_hostname}:{server_port}/test.html") + self.javascript_setup() + if load_pyodide: + self.run_js("await loadPyodide({ indexURL : './'});") + self.save_state() + self.script_timeout = script_timeout + self.driver.set_script_timeout(script_timeout) + + def javascript_setup(self): self.run_js("Error.stackTraceLimit = Infinity;", pyodide_checks=False) self.run_js( """ @@ -155,11 +163,6 @@ class SeleniumWrapper: """, pyodide_checks=False, ) - if load_pyodide: - self.run_js("await loadPyodide({ indexURL : './'});") - self.save_state() - self.script_timeout = script_timeout - self.driver.set_script_timeout(script_timeout) @property def logs(self): diff --git a/src/pyodide-py/pyodide/console.py b/src/pyodide-py/pyodide/console.py index 37ad9ca69..6ef85f78e 100644 --- a/src/pyodide-py/pyodide/console.py +++ b/src/pyodide-py/pyodide/console.py @@ -1,3 +1,4 @@ +import traceback from typing import Optional, Callable, Any, List, Tuple import code import io @@ -221,6 +222,17 @@ class InteractiveConsole(code.InteractiveConsole): self.load_packages_and_run(self.run_complete, source) ) + def num_frames_to_keep(self, tb): + keep_frames = False + kept_frames = 0 + # Try to trim out stack frames inside our code + for (frame, _) in traceback.walk_tb(tb): + keep_frames = keep_frames or frame.f_code.co_filename == "" + keep_frames = keep_frames or frame.f_code.co_filename == "" + if keep_frames: + kept_frames += 1 + return kept_frames + async def load_packages_and_run(self, run_complete, source): try: await run_complete @@ -230,11 +242,12 @@ class InteractiveConsole(code.InteractiveConsole): with self.stdstreams_redirections(): await _load_packages_from_imports(source) try: - result = await eval_code_async(source, self.locals) + result = await eval_code_async( + source, self.locals, filename="" + ) except BaseException as e: - from traceback import print_exception - - print_exception(type(e), e, e.__traceback__) + nframes = self.num_frames_to_keep(e.__traceback__) + traceback.print_exception(type(e), e, e.__traceback__, -nframes) raise e else: self.display(result) diff --git a/src/pyodide.js b/src/pyodide.js index bdb6ca84e..c7713e0cf 100644 --- a/src/pyodide.js +++ b/src/pyodide.js @@ -448,6 +448,9 @@ globalThis.loadPyodide = async function(config = {}) { } }); } + if (Module.on_fatal) { + Module.on_fatal(e); + } } catch (e) { console.error("Another error occurred while handling the fatal error:"); console.error(e); diff --git a/src/templates/console.html b/src/templates/console.html index 500072953..4f511ca70 100644 --- a/src/templates/console.html +++ b/src/templates/console.html @@ -3,9 +3,8 @@ - - - + +