-
Notifications
You must be signed in to change notification settings - Fork 12
Check args more thoroghly in sense_hat.py and mangle traceback for sense_hat.py errors
#1348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
1b0b5ea
3d206a4
d55dea3
164ee52
bb5895d
6df6926
fc02afa
1d20deb
5e8a655
7579ab0
22066bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -340,6 +340,18 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { | |||||||||||||||||||||||||||||||||
| .replace(/\[(.*?)\]/, "") | ||||||||||||||||||||||||||||||||||
| .replace(/\.$/, ""); | ||||||||||||||||||||||||||||||||||
| const errorType = err.tp$name || err.constructor.name; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // If this is an error in the sense_hat.py shim, remove the first line of | ||||||||||||||||||||||||||||||||||
| // the traceback as this will be the line in the shim which we don't want | ||||||||||||||||||||||||||||||||||
| // to show to users, so that the error message will instead point to the | ||||||||||||||||||||||||||||||||||
| // line in the user's code which caused the error. | ||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||
| err.traceback.length > 1 && | ||||||||||||||||||||||||||||||||||
| err.traceback[0].filename === "./sense_hat.py" | ||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||
| err.traceback.shift(); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+346
to
+357
|
||||||||||||||||||||||||||||||||||
| // If this is an error in the sense_hat.py shim, use the next entry in | |
| // the traceback as this will be the line in the shim which we don't want | |
| // to show to users, so that the error message will instead point to the | |
| // line in the user's code which caused the error. | |
| if ( | |
| err.traceback.length > 1 && | |
| fileName === "./sense_hat.py" && | |
| ["RuntimeError", "ValueError"].includes(errorType) | |
| ) { | |
| lineNumber = err.traceback[1].lineno; | |
| fileName = err.traceback[1].filename; | |
| } | |
| // Note: we intentionally avoid rewriting tracebacks originating from | |
| // sense_hat.py, because a user may define their own sense_hat.py file. | |
| // Blindly remapping those errors to another frame can misattribute | |
| // real user-code errors to a different file (e.g. main.py). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good idea, but I think it is vanishingly small that someone would write a sense_hat.py file. It would make testing much more complex, as we'd have to stub the fetch(), which is tricky.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -224,6 +224,80 @@ describe("When an error occurs", () => { | |
| }); | ||
| }); | ||
|
|
||
| describe("When an error originates in the sense_hat shim", () => { | ||
| let store; | ||
|
|
||
| // This initialState sets up a file `sense_hat.py` which contains code that | ||
| // will raise an error if the set_pixel function is called with an x | ||
| // value greater than 7 or less than 0. The `main.py` file then calls this | ||
| // function with an x value of 255, which will cause the error to be raised. | ||
| // | ||
| // This file matches the name looked for in the SkulptRunner | ||
| // (`./sense_hat.py`), so the SkulptRunner should attribute the error to the | ||
| // user's `main.py` file and not the `sense_hat.py` shim file, and set the | ||
| // errorDetails accordingly. | ||
| // | ||
| // This test has to be run this way because the sense hat libray is loaded | ||
|
patch0 marked this conversation as resolved.
Outdated
|
||
| // via `fetch()` from a remote URL, which is hard to do in the test | ||
| // environment. | ||
| beforeEach(() => { | ||
| const middlewares = []; | ||
| const mockStore = configureStore(middlewares); | ||
| const initialState = { | ||
| editor: { | ||
| project: { | ||
| components: [ | ||
| { | ||
|
patch0 marked this conversation as resolved.
|
||
| name: "main", | ||
| extension: "py", | ||
| content: | ||
| "from sense_hat import set_pixel\nset_pixel(255, 0, 0, 0, 0)", | ||
| }, | ||
| { | ||
| name: "sense_hat", | ||
| extension: "py", | ||
| content: | ||
| "def set_pixel(x, y, r, g, b):\n" + | ||
| " if x > 7 or x < 0:\n" + | ||
| " raise ValueError('X position must be between 0 and 7')\n", | ||
| }, | ||
|
Comment on lines
+230
to
+263
|
||
| ], | ||
| image_list: [], | ||
| }, | ||
| codeRunTriggered: true, | ||
| }, | ||
| auth: { user }, | ||
| }; | ||
| store = mockStore(initialState); | ||
| render( | ||
| <Provider store={store}> | ||
| <SkulptRunner active={true} /> | ||
| </Provider>, | ||
| ); | ||
| }); | ||
|
|
||
| test("reports the error at the user's line, not the shim's line", () => { | ||
| expect(store.getActions()).toContainEqual( | ||
| setError( | ||
| "ValueError: X position must be between 0 and 7 on line 2 of main.py", | ||
| ), | ||
| ); | ||
| }); | ||
|
|
||
| test("sets errorDetails pointing to the user's code, not the shim", () => { | ||
| expect(store.getActions()).toContainEqual( | ||
| setErrorDetails({ | ||
| type: "ValueError", | ||
| line: 2, | ||
| file: "main.py", | ||
| description: "X position must be between 0 and 7", | ||
| message: | ||
| "ValueError: X position must be between 0 and 7 on line 2 of main.py", | ||
| }), | ||
| ); | ||
| }); | ||
| }); | ||
|
|
||
| describe("When an error has occurred", () => { | ||
| let mockStore; | ||
| let store; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.