You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+17-3Lines changed: 17 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,5 @@
1
1
# Python Friendly Error Messages
2
2
3
-
Todo:
4
-
- Accessibility of output HTML
5
-
6
3
A small library that explains Python error messages in a friendlier way, inspired by [p5.js's Friendly Error System](https://p5js.org/contribute/friendly_error_system/).
7
4
8
5
It can be used in browser-based editors (like RPF's [Code Editor web component](https://github.com/RaspberryPiFoundation/editor-ui)) or any environment that executes Python code through Pyodide or Skulpt.
@@ -69,6 +66,23 @@ const result = friendlyExplain({
69
66
70
67
See the [demo](docs/README.md) for a full set of examples.
71
68
69
+
## Accessibility
70
+
71
+
`result.html` is built to be accessible by default (with WCAG 2.1 AA in mind):
72
+
73
+
- The whole explanation is one labelled group — `<div class="pfem" role="group" lang="…" aria-labelledby="…">`, named by its title, with `lang` taken from the copydeck so screen readers pronounce localised copy correctly (`3.1.2 Language of Parts`). `role="group"` (not a landmark) keeps things uncluttered when several explanations render on one page
74
+
- The title is deliberately not a heading. Heading level depends on the surrounding page outline, which a library can't know, so the title supplies the group's accessible name instead. If you want it in your heading outline, render your own heading from `result.title` and use `result.html` (or the structured fields) for the body
75
+
- Code is marked up as code; inline tokens use `<code>` and blocks use `<pre><code>`
76
+
- The suggested fix has a visible "Suggested fix" label; the original traceback stays in a native `<details>`/`<summary>`
77
+
- Element ids are randomised per call so `aria-labelledby` remains unambiguous when multiple explanations coexist on a page
78
+
79
+
### Your responsibilities
80
+
81
+
A couple of WCAG 2.1AA requirements can only be met by the host app:
82
+
83
+
- Announce it: the explanation appears in response to running code. For a screen reader to announce it without stealing focus, insert it into a pre-existing live region (`aria-live="polite"` / `role="status"`) that is already in the DOM, or move focus to it
84
+
- Contrast & colour: all styling is yours, ensure text contrast, and don't rely on colours (`.pfem__var`, `.pfem__file`, …) alone to convey meaning
85
+
72
86
## Development
73
87
74
88
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed instructions.
// The error could not be parsed into a structured trace, so there is no friendly
35
-
// explanation to offer. Return null and let the caller fall back to the raw error.
37
+
// The error could not be parsed into a structured trace, so there is no friendly explanation to offer. Return null and let the caller fall back to the raw error
36
38
if(!parsed)returnnull;
37
-
// The runtime-agnostic adapter leaves `runtime: "unknown"`; this adds the concrete
38
-
// runtime we dispatched on so the trace carries the correct label
39
+
// The runtime-agnostic adapter leaves `runtime: "unknown"`; this adds the concrete runtime we dispatched on so the trace carries the correct label
// The error could not be parsed — no friendly explanation; caller uses the raw error.
155
+
// The error could not be parsed — no friendly explanation; caller uses the raw error
149
156
if(!trace)returnnull;
150
157
151
158
// Caller-provided file/line take precedence over whatever was parsed from the trace
152
-
// Useful when the traceback's innermost frame references an internal file (eg.
153
-
// Pyodide's "<exec>") instead of the user's filename, or when the line needs correcting.
159
+
// Useful when the traceback's innermost frame references an internal file (eg. Pyodide's "<exec>") instead of the user's filename, or when the line needs correcting
154
160
if(opts.file!==undefined)trace.file=opts.file;
155
161
if(opts.line!==undefined)trace.line=opts.line;
156
162
157
-
// (Re)derive the code context from the effective line: when the caller overrides the
158
-
// line, or when a pre-parsed trace arrived without a codeLine.
163
+
// (Re)derive the code context from the effective line: when the caller overrides the line, or when a pre-parsed trace arrived without a codeLine
0 commit comments