Skip to content

Commit cf41ea5

Browse files
committed
Trial Actions-built and Pages-hosted demo
1 parent 5204224 commit cf41ea5

File tree

8 files changed

+307
-5
lines changed

8 files changed

+307
-5
lines changed

.github/workflows/pages.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Build and deploy demo to GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: "pages"
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Set up Node
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: 22
28+
29+
- name: Install dependencies
30+
working-directory: demo
31+
run: npm ci
32+
33+
- name: Prepare demo assets
34+
working-directory: demo
35+
run: npm run prepare-demo
36+
37+
- name: Upload artifact
38+
uses: actions/upload-pages-artifact@v3
39+
with:
40+
path: demo
41+
42+
deploy:
43+
runs-on: ubuntu-latest
44+
needs: build
45+
environment:
46+
name: github-pages
47+
url: ${{ steps.deployment.outputs.page_url }}
48+
steps:
49+
- name: Deploy to GitHub Pages
50+
id: deployment
51+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Node / TypeScript
22
node_modules/
33
dist/
4+
vendor/
45
*.log
56
npm-debug.log*
67
yarn-debug.log*

docs/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@raspberrypifoundation:registry=https://npm.pkg.github.com

docs/README.md

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Documentation
22

3-
## Demo
3+
## Hosted demo
44

5-
This directory contains a demo HTML file that showcases the Python Friendly Error Messages library.
5+
https://raspberrypifoundation.github.io/python-friendly-error-messages/
6+
7+
This directory contains a demo `index.html` file that showcases the Python Friendly Error Messages library. This uses a given build of the library.
68

79
The demo shows how the library transforms common Python error traces (from both Skulpt and Pyodide runtimes) into friendly, beginner-friendly explanations. It includes examples of:
810

@@ -20,7 +22,33 @@ Each example shows:
2022
2. The code that caused the error
2123
3. The friendly explanation generated by the library
2224

23-
## Usage
25+
### Usage
26+
27+
This is [handled automatically](../.github/workflows/pages.yml) on the hosted demo, but to run it locally against a specific version of the library:
28+
29+
Set the version of the library in `docs/package.json`, then in this `docs/` directory run:
30+
31+
1. Install the package and prepare the demo:
32+
```bash
33+
npm install
34+
npm run prepare-demo
35+
```
36+
37+
Then in the root directory of the project:
38+
39+
1. Start up a local web server:
40+
```bash
41+
npx http-server -p 8000
42+
```
43+
44+
2. Navigate to `http://localhost:8000/docs/local-demo.html`
45+
46+
47+
## Local demo
48+
49+
The `local-demo.html` file in this directory is a copy of the hosted demo that can be run locally, ie. against the local build of the library. Useful for development and testing.
50+
51+
### Usage
2452

2553
(all commands should be run in the root directory of the project)
2654

@@ -34,5 +62,5 @@ Each example shows:
3462
npx http-server -p 8000
3563
```
3664

37-
3. Navigate to `http://localhost:8000/demo/`
65+
3. Navigate to `http://localhost:8000/docs/local-demo.html`
3866

docs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ <h1>Python Friendly Error Messages - Demo</h1>
1818
</div>
1919

2020
<script type="module">
21-
import { friendlyExplain, loadCopydeck, registerAdapter, loadCopydeckFor, skulptAdapter, pyodideAdapter } from '../dist/index.browser.js';
21+
import { friendlyExplain, loadCopydeck, registerAdapter, loadCopydeckFor, skulptAdapter, pyodideAdapter } from './vendor/python-friendly-error-messages/index.browser.js';
2222

2323
// example traces with corresponding code
2424
const examples = [

docs/local-demo.html

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Python Friendly Error Messages - Local Demo</title>
8+
<link rel="stylesheet" href="styles.css">
9+
</head>
10+
11+
<body>
12+
<div class="container">
13+
<h1>Python Friendly Error Messages - Local Demo</h1>
14+
15+
<div id="demo-container">
16+
Loading demo...
17+
</div>
18+
</div>
19+
20+
<script type="module">
21+
import { friendlyExplain, loadCopydeck, registerAdapter, loadCopydeckFor, skulptAdapter, pyodideAdapter } from '../dist/index.browser.js';
22+
23+
// example traces with corresponding code
24+
const examples = [
25+
{
26+
title: "NameError - Undefined Variable",
27+
runtime: "skulpt",
28+
code: `print("Hello")
29+
print(kittens)`,
30+
trace: `Traceback (most recent call last):
31+
File "main.py", line 2, in <module>
32+
NameError: name 'kittens' is not defined`
33+
},
34+
{
35+
title: "SyntaxError - Missing Colon",
36+
runtime: "skulpt",
37+
code: `for i in range(3)
38+
print(i)`,
39+
trace: `Traceback (most recent call last):
40+
File "main.py", line 1
41+
for i in range(3)
42+
^
43+
SyntaxError: invalid syntax`
44+
},
45+
{
46+
title: "AttributeError - Using .push() on List",
47+
runtime: "pyodide",
48+
code: `items = []
49+
items.push(3)`,
50+
trace: `Traceback (most recent call last):
51+
File "main.py", line 2, in <module>
52+
items.push(3)
53+
AttributeError: 'list' object has no attribute 'push'`
54+
},
55+
{
56+
title: "TypeError - Adding String and Number",
57+
runtime: "pyodide",
58+
code: `age = 10
59+
message = "I am " + age + " years old"`,
60+
trace: `Traceback (most recent call last):
61+
File "main.py", line 2, in <module>
62+
message = "I am " + age + " years old"
63+
TypeError: can only concatenate str (not "int") to str`
64+
},
65+
{
66+
title: "NameError - Variable Used Before Assignment",
67+
runtime: "skulpt",
68+
code: `def calculate():
69+
result = x + 5
70+
x = 10
71+
return result
72+
73+
calculate()`,
74+
trace: `Traceback (most recent call last):
75+
File "main.py", line 5, in <module>
76+
calculate()
77+
File "main.py", line 2, in calculate
78+
UnboundLocalError: local variable 'x' referenced before assignment`
79+
},
80+
{
81+
title: "IndexError - List Index Out of Range",
82+
runtime: "pyodide",
83+
code: `numbers = [1, 2, 3]
84+
print(numbers[5])`,
85+
trace: `Traceback (most recent call last):
86+
File "main.py", line 2, in <module>
87+
print(numbers[5])
88+
IndexError: list index out of range`
89+
},
90+
{
91+
title: "KeyError - Dictionary Key Not Found",
92+
runtime: "skulpt",
93+
code: `person = {"name": "Alice", "age": 30}
94+
print(person["city"])`,
95+
trace: `Traceback (most recent call last):
96+
File "main.py", line 2, in <module>
97+
print(person["city"])
98+
KeyError: 'city'`
99+
},
100+
{
101+
title: "ZeroDivisionError - Division by Zero",
102+
runtime: "pyodide",
103+
code: `result = 10 / 0
104+
print(result)`,
105+
trace: `Traceback (most recent call last):
106+
File "main.py", line 1, in <module>
107+
result = 10 / 0
108+
ZeroDivisionError: division by zero`
109+
}
110+
];
111+
112+
async function initDemo() {
113+
const container = document.getElementById('demo-container');
114+
115+
try {
116+
await loadCopydeckFor('en');
117+
registerAdapter('skulpt', skulptAdapter);
118+
registerAdapter('pyodide', pyodideAdapter);
119+
120+
let html = '<div class="demo__grid">';
121+
122+
for (const example of examples) {
123+
try {
124+
const result = friendlyExplain({
125+
error: example.trace,
126+
code: example.code,
127+
audience: 'beginner',
128+
verbosity: 'standard'
129+
});
130+
131+
html += `
132+
<div class="demo__card">
133+
<h2>
134+
${example.title}
135+
<span class="demo__badge demo__badge--${example.runtime}">${example.runtime}</span>
136+
</h2>
137+
<div class="demo__card-content">
138+
<div class="demo__trace-section">
139+
<h3>Original Trace</h3>
140+
<div class="demo__trace-raw">${escapeHtml(example.trace)}</div>
141+
</div>
142+
<div class="demo__trace-section">
143+
<h3>Original Code</h3>
144+
<div class="demo__code-example">${escapeHtml(example.code)}</div>
145+
</div>
146+
<div class="demo__explanation">
147+
<h3>Friendly Explanation</h3>
148+
${result.html}
149+
</div>
150+
</div>
151+
</div>
152+
`;
153+
} catch (err) {
154+
html += `
155+
<div class="demo__card">
156+
<h2>${example.title}</h2>
157+
<div class="demo__error">Error processing: ${escapeHtml(err.message)}</div>
158+
</div>
159+
`;
160+
}
161+
}
162+
163+
html += '</div>';
164+
container.innerHTML = html;
165+
166+
// click handlers for collapsible cards
167+
const cards = container.querySelectorAll('.demo__card');
168+
cards.forEach(card => {
169+
const h2 = card.querySelector('h2');
170+
if (h2) {
171+
h2.addEventListener('click', () => {
172+
card.classList.toggle('demo__card--expanded');
173+
});
174+
}
175+
});
176+
} catch (err) {
177+
container.innerHTML = `<div class="demo__error">Failed to load demo: ${escapeHtml(err.message)}</div>`;
178+
}
179+
}
180+
181+
function escapeHtml(text) {
182+
const div = document.createElement('div');
183+
div.textContent = text;
184+
return div.innerHTML;
185+
}
186+
187+
initDemo();
188+
</script>
189+
</body>
190+
191+
</html>

docs/package-lock.json

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "python-friendly-error-messages-demo",
3+
"version": "0.0.1",
4+
"scripts": {
5+
"prepare-demo": "mkdir -p ./vendor/python-friendly-error-messages && cp ./node_modules/@raspberrypifoundation/python-friendly-error-messages/dist/index.browser.js ./vendor/python-friendly-error-messages/index.browser.js"
6+
},
7+
"dependencies": {
8+
"@raspberrypifoundation/python-friendly-error-messages": "^0.1.3"
9+
}
10+
}

0 commit comments

Comments
 (0)