Skip to content

Commit 40cfd10

Browse files
authored
Merge pull request #127 from realpython/brython
Brython
2 parents 508ab4d + bb31ef0 commit 40cfd10

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+125409
-0
lines changed

brython/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.Makefile

brython/README.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Brython Examples
2+
3+
This set of examples is intended to accompany the [Real Python](https://realpython.com/) tutorial [Brython: Python in Your Browser](https://realpython.com/brython-python-in-browser).
4+
5+
Most of the examples are found in the article and others are extras that did not fit in the scope of the article.
6+
7+
## async
8+
9+
* Project demonstrating how to use Brython asynchronous functions to request data from a server API
10+
* In the following examples, the API is a simple text file that returns the text "Real Python"
11+
* To test the examples, execute a local web server in the respective directory
12+
* The recommended Python development server is started with: `python -m http.server`
13+
* https://realpython.com/brython-python-in-browser/#applying-asynchronous-development-in-brython
14+
15+
### aio
16+
17+
* Demonstrates the usage of `browser.aio`, the substitute to `asyncio` in Brython
18+
* This example is in the tutorial: https://realpython.com/brython-python-in-browser/#async-io-in-brython
19+
* https://www.brython.info/static_doc/en/aio.html
20+
21+
### ajax
22+
23+
* Demonstrates the usage of `browser.ajax`
24+
* This example is in the tutorial: https://realpython.com/brython-python-in-browser/#ajax-in-brython
25+
* https://www.brython.info/static_doc/en/ajax.html
26+
27+
### fetch
28+
29+
* Demonstrates the usage of JavaScript `fetch` from Brython
30+
* This example is not in the tutorial and is provided as an extra. It is related to this section: https://realpython.com/brython-python-in-browser/#applying-asynchronous-development-in-brython
31+
32+
## Base64
33+
34+
Examples demonstrating how to access the DOM API starting from an app that takes a string as input, generates the Base64-encoded value of the string, and displays it on the page. Each example is slightly different as stated in the following sections.
35+
36+
### embed
37+
38+
* The application is a single `index.htm` with embedded Python code. It can be executed by opening the file with an internet browser. Starting a local web server is not required
39+
* The user enters the string to be encoded through the standard prompt message box of the browser.
40+
* This example is the same as the following one but with the Python code embedded in HTML.
41+
* It is not in the tutorial in this format, but relates to https://realpython.com/brython-python-in-browser/#the-dom-api-in-brython
42+
43+
### sep
44+
45+
* This project is the same as `embed`, but the Python code is a separate file, `main.py`.
46+
* A separate Python file requires starting a local server to test this example (`python3 -m http.server`).
47+
48+
### form
49+
50+
* The application is an `index.html` with the Python code in a separate `main.py` file. Starting a local webserver is required (`python3 -m http.server`)
51+
* The user enters the string in the HTML form of the main page
52+
* You can find this example in the tutorial: https://realpython.com/brython-python-in-browser/#the-dom-api-in-brython
53+
54+
### storage
55+
56+
* This example is an extension of the **form** project demonstrating how to use `localstorage` and save the data between page reload. It requires to start a local web server (`python3 -m http.server`).
57+
* The data is saved as a JSON document associated with a single key of the local storage. The performance is degraded as you add more elements in the JSON file.
58+
* This example is documented in the tutorial: https://realpython.com/brython-python-in-browser/#browser-web-api
59+
60+
### storage_perf
61+
62+
* In an attempt to overcome the performance issue of the `storage` example, this example saves each base64 encoded value into a separate key. The key is the original string entered by the user.
63+
* This example is an extra and not described in the tutorial but is related to https://realpython.com/brython-python-in-browser/#browser-web-api
64+
65+
## chrome_extensions
66+
67+
### hello_js
68+
69+
* Example of a JavaScript Google Chrome extension
70+
* In the tutorial: https://realpython.com/brython-python-in-browser/#hello-world-extension-in-js
71+
72+
### hello_py
73+
74+
* Same example as hello_js using Brython
75+
* In the tutorial: https://realpython.com/brython-python-in-browser/#hello-world-extension-in-python
76+
77+
## console
78+
79+
* Brython console as an iframe embedded in an HTML file. Does not require to run a local web server. Opening `index.html` with a browser is sufficient to test it.
80+
* This is an extra not described in the tutorial.
81+
* Check out https://brython.info/console.html to see it online.
82+
83+
## github_install
84+
85+
* `index.html` loading the Brython engine from GitHub. You can open the file directly. It only displays a message box with "Hello Real Python."
86+
* In the tutorial: https://realpython.com/brython-python-in-browser/#github-installation
87+
88+
## hashes
89+
90+
* In the same vein as the Base64 encode application, this one generates the hash, SHA-1, SHA-256 or SHA-512, of a string. It adds a dropdown to select the desired algorithm (SHA-1, SHA-256, or SHA-512).
91+
* This serves as the basis for a translation to the same application with Vue.js (see **vuejs** project below).
92+
* It requires a local web server.
93+
* This is an extra not described in the tutorial, but serves the bases as the Vue.js example and you can read about it at https://realpython.com/brython-python-in-browser/#web-ui-framework
94+
95+
## import
96+
97+
* Shows how to import an external Python module. The external module is `functional.py`. The main Python code is embedded in the HTML page.
98+
* It requires a local web server.
99+
* Read about it in the tutorial: https://realpython.com/brython-python-in-browser/#import-in-brython
100+
101+
## import_js
102+
103+
* Expands on the `import` example by allowing the creation of `brython_module.js` generated with `brython-cli --modules`.
104+
* This requires a Python virtual environment with Brython installed (`pip install brython`) to have `brython-cli` available in the PATH. The generated files are available in the sub-directory `dist_example`.
105+
* You can open `dist_example/index.html` with a browser, without the need for a webserver to run locally, because the dependencies are only JS files (`brython.js` and `brython_modules.js`).
106+
* You can read more about this approach in the tutorial at https://realpython.com/brython-python-in-browser/#reduce-import-size
107+
108+
## npm_install
109+
110+
* Example of a Brython project installed with npm. See the corresponding tutorial section for more details.
111+
* Tutorial section: https://realpython.com/brython-python-in-browser/#npm-install
112+
113+
## pip_install
114+
115+
* Example of a Brython project installed with `pip`.
116+
* Tutorial section: https://realpython.com/brython-python-in-browser/#pypi-install
117+
118+
## sha256
119+
120+
* Application to generate the SHA-256 hash of a given string. The data is stored as JSON in a key of the localstorage to preserve the calculations between page reloads.
121+
* This is an extra not described in the tutorial, but serves the basis of the Vue.js example. You can read about it at https://realpython.com/brython-python-in-browser/#web-ui-framework
122+
123+
## vuejs
124+
125+
* Brython and Vue.js implementation of `hashes`. Requires a local web server to be running.
126+
* The Vue.js example is documented at https://realpython.com/brython-python-in-browser/#web-ui-framework
127+
128+
## wasm
129+
130+
* An example demonstrating the generation of a WASM file, the loading of the file, and usage of the function from Brython. The source code of the WASM file is Rust.
131+
* This requires you to have the Rust compiler installed on a local machine. Check the details in the Brython tutorial. A local web server is needed as it requires loading the wasm file.
132+
* The web server can be started in the directory `wasm/op/web`. The debug wasm file is included. This is only for demonstration. The `add` function does not handle negative and big integers.
133+
* Documented in the tutorial at https://realpython.com/brython-python-in-browser/#webassembly
134+
135+
## zero_install
136+
137+
* An example demonstrating a minimum Brython project. The Brython engine is fetched from a CDN, and the Python code is embedded on the page. No need for a local web server, no need for a local Python environment either, just a browser with JavaScript enabled :-)
138+
* In the tutorial at https://realpython.com/brython-python-in-browser/#cdn-server-install

brython/async/aio/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Real Python

brython/async/aio/index.html

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!DOCTYPE html >
2+
<html>
3+
<head>
4+
<meta charset="utf-8"/>
5+
<link
6+
rel="stylesheet"
7+
href="https://cdnjs.cloudflare.com/ajax/libs/pure/2.0.3/pure-min.min.css"
8+
integrity="sha256-jYujp4Kf07YDuUF9i1MHo4AnpXUKuHxIUXH7CrHxdKw="
9+
crossorigin="anonymous" />
10+
<script
11+
src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.8.9/brython.min.js" defer>
12+
</script>
13+
<script
14+
src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.8.9/brython_stdlib.min.js" defer>
15+
</script>
16+
<script src="main.py" type="text/python" defer></script>
17+
<style>
18+
body { padding: 30px; }
19+
aside {
20+
background: lightyellow;
21+
margin: 1em 0;
22+
padding: .3em 1em;
23+
border-radius: 3px;
24+
border: 1px solid gray;
25+
color: gray;
26+
}
27+
</style>
28+
</head>
29+
<body onload="brython(1)">
30+
<h2>Aio Requests</h2>
31+
<aside><p>Demonstrate the usage of GET using <tt>browser.aio</tt>.
32+
You need to start a server for this example to work.
33+
You can start the Python development web server with the following command:
34+
<tt>python3 -m http.server</tt>.
35+
</p></aside>
36+
<form class="pure-form" onsubmit="return false;">
37+
<legend>Actions</legend>
38+
<button id="get-btn" class="pure-button pure-button-primary">Async Get</button>
39+
<legend>Logs</legend>
40+
<textarea id="log" name="log" rows="20" cols="60"></textarea>
41+
</form>
42+
</body>
43+
44+
</html>

brython/async/aio/index1.html

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!DOCTYPE html >
2+
<html>
3+
<head>
4+
<meta charset="utf-8"/>
5+
<link
6+
rel="stylesheet"
7+
href="https://cdnjs.cloudflare.com/ajax/libs/pure/2.0.3/pure-min.min.css"
8+
integrity="sha256-jYujp4Kf07YDuUF9i1MHo4AnpXUKuHxIUXH7CrHxdKw="
9+
crossorigin="anonymous" />
10+
<script
11+
src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.8.9/brython.min.js" defer>
12+
</script>
13+
<script
14+
src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.8.9/brython_stdlib.min.js" defer>
15+
</script>
16+
<style>
17+
body { padding: 30px; }
18+
aside {
19+
background: lightyellow;
20+
margin: 1em 0;
21+
padding: .3em 1em;
22+
border-radius: 3px;
23+
border: 1px solid gray;
24+
color: gray;
25+
}
26+
</style>
27+
</head>
28+
<body onload="brython(1)">
29+
<h2>Aio Requests</h2>
30+
<aside><p>Demonstrate the usage of GET using <tt>browser.aio</tt>.
31+
You need to start a server for this example to work.
32+
You can start the Python development web server with the following command:
33+
<tt>python3 -m http.server</tt>.
34+
</p></aside>
35+
<form class="pure-form" onsubmit="return false;">
36+
<legend>Actions</legend>
37+
<button id="get-btn" class="pure-button pure-button-primary">Async Get</button>
38+
<button id="clear-logs-btn" class="pure-button">Clear Logs</button>
39+
<legend>Logs</legend>
40+
<textarea id="log" name="log" rows="20" cols="60"></textarea>
41+
</form>
42+
<script type="text/python">
43+
from browser import aio, document
44+
import javascript
45+
46+
def counter():
47+
x = 1
48+
while True:
49+
yield x
50+
x += 1
51+
52+
cnt = counter()
53+
54+
def log(message):
55+
document["log"].value += f"{next(cnt):03}: {message} \n"
56+
57+
def add_log_sep():
58+
log_text = document["log"].value
59+
if not log_text:
60+
return
61+
else:
62+
document["log"].value += "======================================\n"
63+
64+
def clear_logs(evt):
65+
global cnt
66+
cnt = counter() # Reset counter
67+
document["log"].value = ""
68+
69+
async def process_get(url):
70+
log("Start process_get")
71+
log("Before await aio.get")
72+
req = await aio.get(url)
73+
log(f"Retrieved data: '{req.data}'")
74+
log("End process_get")
75+
76+
def aio_get(evt):
77+
add_log_sep()
78+
log("Before aio.run")
79+
aio.run(process_get("/api.txt"))
80+
log("After aio.run")
81+
82+
document["get-btn"].bind("click", aio_get)
83+
document["clear-logs-btn"].bind("click", clear_logs)
84+
</script>
85+
</body>
86+
87+
</html>

brython/async/aio/main.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from browser import aio, document
2+
3+
4+
def log(message):
5+
document["log"].value += f"{message} \n"
6+
7+
8+
async def process_get(url):
9+
log("Before await aio.get")
10+
req = await aio.get(url)
11+
log(f"Retrieved data: '{req.data}'")
12+
13+
14+
def aio_get(evt):
15+
log("Before aio.run")
16+
aio.run(process_get("/api.txt"))
17+
log("After aio.run")
18+
19+
20+
document["get-btn"].bind("click", aio_get)

brython/async/ajax/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Real Python

brython/async/ajax/index.html

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<!DOCTYPE html >
2+
<html>
3+
<head>
4+
<meta charset="utf-8"/>
5+
<link
6+
rel="stylesheet"
7+
href="https://cdnjs.cloudflare.com/ajax/libs/pure/2.0.3/pure-min.min.css"
8+
integrity="sha256-jYujp4Kf07YDuUF9i1MHo4AnpXUKuHxIUXH7CrHxdKw="
9+
crossorigin="anonymous" />
10+
<script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js" defer></script>
11+
<script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython_stdlib.min.js" defer></script>
12+
<style>
13+
body { padding: 30px; }
14+
aside {
15+
background: lightyellow;
16+
margin: 1em 0;
17+
padding: .3em 1em;
18+
border-radius: 3px;
19+
border: 1px solid gray;
20+
color: gray;
21+
}
22+
</style>
23+
</head>
24+
<body onload="brython(1)">
25+
<h2>Ajax Requests</h2>
26+
<aside><p>Demonstrate the usage of GET using <tt>browser.ajax</tt>.
27+
You need to start a server for this example to work.
28+
You can start the Python development web server with the following command:
29+
<tt>python3 -m http.server</tt>.
30+
</p></aside>
31+
<form class="pure-form" onsubmit="return false;">
32+
<legend>Actions</legend>
33+
<button id="get-btn" class="pure-button pure-button-primary">Async Get</button>
34+
<button id="get-blocking-btn" class="pure-button pure-button-primary">Blocking Get</button>
35+
<button id="clear-logs-btn" class="pure-button">Clear Logs</button>
36+
<legend>Logs</legend>
37+
<textarea id="log" name="log" rows="20" cols="60"></textarea>
38+
</form>
39+
<script type="text/python">
40+
from browser import ajax, document
41+
import javascript
42+
43+
def counter():
44+
x = 1
45+
while True:
46+
yield x
47+
x += 1
48+
49+
cnt = counter()
50+
51+
def on_complete(req):
52+
if req.status == 200:
53+
log(f"Text received: '{req.text}'")
54+
elif req.status == 0:
55+
error = f"Error: Did you start a web server (ex: 'python3 -m http.server')?"
56+
log(error)
57+
else:
58+
error = f"Error: {req.status} - {req.text}"
59+
60+
def log(message):
61+
document["log"].value += f"{next(cnt):03}: {message} \n"
62+
63+
def add_log_sep():
64+
log_text = document["log"].value
65+
if not log_text:
66+
return
67+
else:
68+
document["log"].value += "======================================\n"
69+
70+
def clear_logs(evt):
71+
global cnt
72+
cnt = counter() # Reset counter
73+
document["log"].value = ""
74+
75+
def ajax_get(evt):
76+
add_log_sep()
77+
log("Before async get")
78+
ajax.get("/api.txt", oncomplete=on_complete)
79+
log("After async get")
80+
81+
def ajax_get_blocking(evt):
82+
add_log_sep()
83+
log("Before blocking get")
84+
try:
85+
ajax.get("/api.txt", blocking=True, oncomplete=on_complete)
86+
except Exception as exc:
87+
error = f"Error: {exc.__name__} - Did you start a web server (ex: 'python3 -m http.server')?"
88+
log(error)
89+
else:
90+
log("After blocking get")
91+
92+
document["get-btn"].bind("click", ajax_get)
93+
document["get-blocking-btn"].bind("click", ajax_get_blocking)
94+
document["clear-logs-btn"].bind("click", clear_logs)
95+
</script>
96+
</body>
97+
98+
</html>

0 commit comments

Comments
 (0)