10 Brython
11 Brython 예제
이 예제 모음은 Real Python 튜토리얼 Brython: 브라우저 속의 파이썬을 보충하기 위한 것입니다.
대부분의 예제는 기사에서 찾을 수 있으며, 일부는 기사 범위에 맞지 않아 추가된 내용입니다.
11.1 async
- Brython 비동기 함수를 사용하여 서버 API에서 데이터를 요청하는 방법을 보여주는 프로젝트
- 다음 예제에서 API는 “Real Python”이라는 텍스트를 반환하는 간단한 텍스트 파일입니다.
- 예제를 테스트하려면 각 디렉토리에서 로컬 웹 서버를 실행하십시오.
- 권장되는 Python 개발 서버는 다음 명령으로 시작합니다:
python -m http.server - https://realpython.com/brython-python-in-browser/#applying-asynchronous-development-in-brython
11.1.1 aio
- Brython에서
asyncio를 대체하는browser.aio의 사용법을 보여줍니다. - 이 예제는 튜토리얼에 있습니다: https://realpython.com/brython-python-in-browser/#async-io-in-brython
- https://www.brython.info/static_doc/en/aio.html
11.1.2 ajax
browser.ajax의 사용법을 보여줍니다.- 이 예제는 튜토리얼에 있습니다: https://realpython.com/brython-python-in-browser/#ajax-in-brython
- https://www.brython.info/static_doc/en/ajax.html
11.1.3 fetch
- Brython에서 JavaScript
fetch를 사용하는 방법을 보여줍니다. - 이 예제는 튜토리얼에 없으며 추가로 제공됩니다. 이 섹션과 관련이 있습니다: https://realpython.com/brython-python-in-browser/#applying-asynchronous-development-in-brython
11.2 Base64
문자열을 입력으로 받아 문자열의 Base64 인코딩 값을 생성하고 페이지에 표시하는 앱부터 시작하여 DOM API에 액세스하는 방법을 보여주는 예제입니다. 각 예제는 다음 섹션에 설명된 대로 약간 다릅니다.
11.2.1 embed
- 이 애플리케이션은 Python 코드가 내장된 단일
index.htm입니다. 인터넷 브라우저로 파일을 열어 실행할 수 있습니다. 로컬 웹 서버를 시작할 필요가 없습니다. - 사용자는 브라우저의 표준 프롬프트 메시지 상자를 통해 인코딩할 문자열을 입력합니다.
- 이 예제는 다음 예제와 동일하지만 Python 코드가 HTML에 내장되어 있습니다.
- 이 형식으로는 튜토리얼에 없지만 https://realpython.com/brython-python-in-browser/#the-dom-api-in-brython 와 관련이 있습니다.
11.2.2 sep
- 이 프로젝트는
embed와 동일하지만 Python 코드가 별도의 파일인main.py에 있습니다. - 이 예제를 테스트하려면 별도의 Python 파일이 필요하므로 로컬 서버를 시작해야 합니다 (
python3 -m http.server).
11.2.3 form
- 이 애플리케이션은 Python 코드가 별도의
main.py파일에 있는index.html입니다. 로컬 웹 서버를 시작해야 합니다 (python3 -m http.server). - 사용자는 메인 페이지의 HTML 양식에 문자열을 입력합니다.
- 이 예제는 튜토리얼에서 찾을 수 있습니다: https://realpython.com/brython-python-in-browser/#the-dom-api-in-brython
11.2.4 storage
- 이 예제는
localstorage를 사용하고 페이지 새로고침 사이에 데이터를 저장하는 방법을 보여주는 form 프로젝트의 확장입니다. 로컬 웹 서버를 시작해야 합니다 (python3 -m http.server). - 데이터는 로컬 저장소의 단일 키와 연결된 JSON 문서로 저장됩니다. JSON 파일에 더 많은 요소를 추가하면 성능이 저하됩니다.
- 이 예제는 튜토리얼에 설명되어 있습니다: https://realpython.com/brython-python-in-browser/#browser-web-api
11.2.5 storage_perf
storage예제의 성능 문제를 극복하기 위해 이 예제는 각 base64 인코딩된 값을 별도의 키에 저장합니다. 키는 사용자가 입력한 원래 문자열입니다.- 이 예제는 추가 사항이며 튜토리얼에 설명되어 있지 않지만 https://realpython.com/brython-python-in-browser/#browser-web-api 와 관련이 있습니다.
11.3 chrome_extensions
11.3.1 hello_js
- JavaScript Google Chrome 확장 프로그램 예제
- 튜토리얼: https://realpython.com/brython-python-in-browser/#hello-world-extension-in-js
11.3.2 hello_py
- Brython을 사용하는 hello_js와 동일한 예제
- 튜토리얼: https://realpython.com/brython-python-in-browser/#hello-world-extension-in-python
11.4 console
- HTML 파일에 내장된 iframe으로서의 Brython 콘솔. 로컬 웹 서버를 실행할 필요가 없습니다. 브라우저로
index.html을 여는 것만으로 테스트할 수 있습니다. - 이것은 튜토리얼에 설명되지 않은 추가 사항입니다.
- 온라인에서 보려면 https://brython.info/console.html 을 확인하십시오.
11.5 github_install
- GitHub에서 Brython 엔진을 로드하는
index.html. 파일을 직접 열 수 있습니다. “Hello Real Python”이라는 메시지 상자만 표시됩니다. - 튜토리얼: https://realpython.com/brython-python-in-browser/#github-installation
11.6 hashes
- Base64 인코딩 애플리케이션과 마찬가지로, 이 애플리케이션은 문자열의 해시(SHA-1, SHA-256 또는 SHA-512)를 생성합니다. 원하는 알고리즘(SHA-1, SHA-256 또는 SHA-512)을 선택하기 위한 드롭다운을 추가합니다.
- 이것은 Vue.js를 사용한 동일한 애플리케이션으로의 번역을 위한 기반이 됩니다 (아래 vuejs 프로젝트 참조).
- 로컬 웹 서버가 필요합니다.
- 이것은 튜토리얼에 설명되지 않은 추가 사항이지만 Vue.js 예제의 기반이 되며 https://realpython.com/brython-python-in-browser/#web-ui-framework 에서 읽을 수 있습니다.
11.7 import
- 외부 Python 모듈을 가져오는 방법을 보여줍니다. 외부 모듈은
functional.py입니다. 기본 Python 코드는 HTML 페이지에 내장되어 있습니다. - 로컬 웹 서버가 필요합니다.
- 튜토리얼에서 읽어보십시오: https://realpython.com/brython-python-in-browser/#import-in-brython
11.8 import_js
brython-cli --modules로 생성된brython_module.js를 생성할 수 있도록 하여import예제를 확장합니다.- 이를 위해서는 PATH에서
brython-cli를 사용할 수 있도록 Brython이 설치된 Python 가상 환경이 필요합니다 (pip install brython). 생성된 파일은dist_example하위 디렉토리에서 사용할 수 있습니다. dist_example/index.html을 브라우저로 열 수 있으며, 종속성이 JS 파일(brython.js및brython_modules.js)뿐이므로 로컬에서 웹 서버를 실행할 필요가 없습니다.- 이 접근 방식에 대한 자세한 내용은 https://realpython.com/brython-python-in-browser/#reduce-import-size 에서 튜토리얼을 참조하십시오.
11.9 npm_install
- npm으로 설치된 Brython 프로젝트 예제. 자세한 내용은 해당 튜토리얼 섹션을 참조하십시오.
- 튜토리얼 섹션: https://realpython.com/brython-python-in-browser/#npm-install
11.10 pip_install
pip으로 설치된 Brython 프로젝트 예제.- 튜토리얼 섹션: https://realpython.com/brython-python-in-browser/#pypi-install
11.11 sha256
- 주어진 문자열의 SHA-256 해시를 생성하는 애플리케이션. 데이터는 페이지 새로고침 간에 계산을 보존하기 위해 로컬 저장소의 키에 JSON으로 저장됩니다.
- 이것은 튜토리얼에 설명되지 않은 추가 사항이지만 Vue.js 예제의 기반이 됩니다. https://realpython.com/brython-python-in-browser/#web-ui-framework 에서 읽을 수 있습니다.
11.12 vuejs
hashes의 Brython 및 Vue.js 구현. 실행하려면 로컬 웹 서버가 필요합니다.- Vue.js 예제는 https://realpython.com/brython-python-in-browser/#web-ui-framework 에 설명되어 있습니다.
11.13 wasm
- WASM 파일 생성, 파일 로드 및 Brython에서 함수 사용을 보여주는 예제. WASM 파일의 소스 코드는 Rust입니다.
- 이를 위해서는 로컬 머신에 Rust 컴파일러가 설치되어 있어야 합니다. Brython 튜토리얼에서 자세한 내용을 확인하십시오. wasm 파일을 로드해야 하므로 로컬 웹 서버가 필요합니다.
- 웹 서버는
wasm/op/web디렉토리에서 시작할 수 있습니다. 디버그 wasm 파일이 포함되어 있습니다. 이것은 데모용입니다.add함수는 음수 및 큰 정수를 처리하지 않습니다. - 튜토리얼에 설명되어 있습니다: https://realpython.com/brython-python-in-browser/#webassembly
11.14 zero_install
- 최소한의 Brython 프로젝트를 보여주는 예제. Brython 엔진은 CDN에서 가져오고 Python 코드는 페이지에 내장됩니다. 로컬 웹 서버도, 로컬 Python 환경도 필요 없으며 JavaScript가 활성화된 브라우저만 있으면 됩니다 :-)
- 튜토리얼: https://realpython.com/brython-python-in-browser/#cdn-server-install
11.15 파일: async/aio/main.py
from browser import aio, document
def log(message):
document["log"].value += f"{message} \n"
async def process_get(url):
log("Before await aio.get")
req = await aio.get(url)
log(f"Retrieved data: '{req.data}'")
def aio_get(evt):
log("Before aio.run")
aio.run(process_get("/api.txt"))
log("After aio.run")
document["get-btn"].bind("click", aio_get)11.16 파일: async/ajax/main.py
from browser import ajax, document
def show_text(req):
if req.status == 200:
log(f"Text received: '{req.text}'")
else:
log(f"Error: {req.status} - {req.text}")
def log(message):
document["log"].value += f"{message} \n"
def ajax_get(evt):
log("Before async get")
ajax.get("/api.txt", oncomplete=show_text)
log("After async get")
def ajax_get_blocking(evt):
log("Before blocking get")
try:
ajax.get("/api.txt", blocking=True, oncomplete=show_text)
except Exception as exc:
log(f"Error: {exc.__name__}")
log("Did you start a web server (ex: 'python3 -m http.server')?")
else:
log("After blocking get")
document["get-btn"].bind("click", ajax_get)
document["get-blocking-btn"].bind("click", ajax_get_blocking)11.17 파일: base64/form/main.py
import base64
from browser import alert, document, html
b64_map = {}
def base64_compute(evt):
value = document["text-src"].value
if not value:
alert("You need to enter a value")
return
if value in b64_map:
alert(
f"The base64 value of '{value}' already exists: '{b64_map[value]}'"
)
return
b64data = base64.b64encode(value.encode()).decode()
b64_map[value] = b64data
display_map()
def clear_map(evt):
b64_map.clear()
document["b64-display"].clear()
def display_map():
table = html.TABLE(Class="pure-table")
table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
table <= (html.TR(html.TD(key) + html.TD(b64_map[key])) for key in b64_map)
base64_display = document["b64-display"]
base64_display.clear()
base64_display <= table
document["text-src"].value = ""
document["submit"].bind("click", base64_compute)
document["clear-btn"].bind("click", clear_map)11.18 파일: base64/sep/main.py
import base64
from browser import document, html, prompt # type: ignore
b64_map = {}
def base64_compute(_) -> None:
default = "Real Python"
data = prompt("Enter a string:", default)
data = data or default
b64data = base64.b64encode(data.encode()).decode()
b64_map[data] = b64data
display_map()
def display_map() -> None:
table = html.TABLE(style={"border": "1 solid grey"})
table <= html.TR(html.TH("Text") + html.TH("Base64"))
table <= (html.TR(html.TD(key) + html.TD(b64_map[key])) for key in b64_map)
base64_display = document["b64-display"]
base64_display.clear()
base64_display <= table
document["b64-btn"].bind("click", base64_compute)11.19 파일: base64/storage/main.py
import base64
import json
from browser import alert, document, html
from browser.local_storage import storage
def load_data():
data = storage.get("b64data")
if data:
b64_map = json.loads(data)
else:
storage["b64data"] = json.dumps({})
b64_map = {}
return b64_map
def base64_compute(evt):
value = document["text-src"].value
if not value:
alert("You need to enter a value")
return
if value in b64_map:
alert(
f"The base64 value of '{value}' already exists: '{b64_map[value]}'"
)
return
b64data = base64.b64encode(value.encode()).decode()
b64_map[value] = b64data
storage["b64data"] = json.dumps(b64_map)
display_map()
def clear_map(evt):
b64_map.clear()
storage["b64data"] = json.dumps({})
document["b64-display"].clear()
def display_map():
if not b64_map:
return
table = html.TABLE(Class="pure-table")
table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
table <= (html.TR(html.TD(key) + html.TD(b64_map[key])) for key in b64_map)
base64_display = document["b64-display"]
base64_display.clear()
base64_display <= table
document["text-src"].value = ""
b64_map = load_data()
display_map()
document["submit"].bind("click", base64_compute)
document["clear-btn"].bind("click", clear_map)11.20 파일: base64/storage_perf/main.py
import base64
from browser import alert, document, html
from browser.local_storage import storage
def load_data():
b64_map = {}
for key in storage.keys():
b64_map[key] = storage.get(key)
return b64_map
def save_data(key, value):
storage[key] = value
def base64_compute(evt):
key = document["text-src"].value
if not key:
alert("You need to enter a value")
return
if key in b64_map:
alert(f"The base64 value of '{key}' already exists: '{b64_map[key]}'")
return
b64data = base64.b64encode(key.encode()).decode()
b64_map[key] = b64data
display_map()
save_data(key, b64data)
def clear_map(evt):
b64_map.clear()
storage.clear()
document["b64-display"].clear()
def display_map():
if not b64_map:
return
table = html.TABLE(Class="pure-table")
table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
table <= (html.TR(html.TD(key) + html.TD(b64_map[key])) for key in b64_map)
base64_display = document["b64-display"]
base64_display.clear()
base64_display <= table
document["text-src"].value = ""
b64_map = load_data()
display_map()
document["submit"].bind("click", base64_compute)
document["clear-btn"].bind("click", clear_map)11.21 파일: chrome_extensions/hello_py/popup.py
from browser import document, prompt
def hello(evt):
default = "Real Python"
name = prompt("Enter your name:", default)
if not name:
name = default
document["hello"].innerHTML = f"Hello, {name}!"
document["hello-btn"].bind("click", hello)11.22 파일: hashes/main.py
import hashlib
from browser import alert, document, html
hashes = {
"sha-1": hashlib.sha1,
"sha-256": hashlib.sha256,
"sha-512": hashlib.sha512,
}
def compute_hash(evt):
value = document["text-src"].value
if not value:
alert("You need to enter a value")
return
algo_dropdown = document["algo"]
algo = algo_dropdown.options[algo_dropdown.selectedIndex].value
hash_object = hashes[algo]()
hash_object.update(value.encode())
hex_value = hash_object.hexdigest()
display_hash(hex_value)
def display_hash(hex_value):
text = html.P(hex_value)
hash_display = document["hash-display"]
hash_display.clear()
hash_display <= text
document["submit"].bind("click", compute_hash)11.23 파일: import/functional.py
# main.py
import itertools
def take(n, iterable):
"Return first n items of the iterable as a list"
return list(itertools.islice(iterable, n))11.24 파일: import_js/functional.py
# functional.py
import itertools
def take(n, iterable):
"Return first n items of the iterable as a list"
return list(itertools.islice(iterable, n))11.25 파일: sha256/main.py
import hashlib
import json
from browser import alert, document, html
from browser.local_storage import storage
LOCAL_STORAGE = "hashdata"
def load_data():
data = storage.get(LOCAL_STORAGE)
if data:
hash_map = json.loads(data)
else:
storage[LOCAL_STORAGE] = json.dumps({})
hash_map = {}
return hash_map
def compute(evt):
value = document["text-src"].value
if not value:
alert("You need to enter a value")
return
if value in hash_map:
alert(
f"The SHA-256 value of '{value}' already exists: '{hash_map[value]}'"
)
return
hash = hashlib.sha256()
hash.update(value.encode())
hash_hex = hash.hexdigest()
hash_map[value] = hash_hex
storage[LOCAL_STORAGE] = json.dumps(hash_map)
display_map()
def clear_map(evt):
hash_map.clear()
storage[LOCAL_STORAGE] = json.dumps({})
document["hash-display"].clear()
def display_map():
if not hash_map:
return
table = html.TABLE(Class="pure-table")
table <= html.THEAD(html.TR(html.TH("Text") + html.TH("SHA-256")))
table <= (
html.TR(html.TD(key) + html.TD(hash_map[key])) for key in hash_map
)
hash_display = document["hash-display"]
hash_display.clear()
hash_display <= table
document["text-src"].value = ""
hash_map = load_data()
display_map()
document["submit"].bind("click", compute)
document["clear-btn"].bind("click", clear_map)11.26 파일: vuejs/main.py
import hashlib
from browser import alert, window
from javascript import this
hashes = {
"sha-1": hashlib.sha1,
"sha-256": hashlib.sha256,
"sha-512": hashlib.sha512,
}
Vue = window.Vue
def compute_hash(evt):
value = this().input_text
if not value:
alert("You need to enter a value")
return
hash_object = hashes[this().algo]()
hash_object.update(value.encode())
hex_value = hash_object.hexdigest()
this().hash_value = hex_value
def created():
for name in hashes:
this().algos.append(name)
this().algo = next(iter(hashes))
app = Vue.createApp(
{
"el": "#app",
"created": created,
"data": lambda _: {
"hash_value": "",
"algos": [],
"algo": "",
"input_text": "",
},
"methods": {"compute_hash": compute_hash},
}
)
app.mount("#app")11.27 파일: wasm/op/web/main.py
from browser import document, window
double_first_and_add = None
def add_rust_fn(module):
global double_first_and_add
double_first_and_add = module.instance.exports.double_first_and_add
def add_numbers(evt):
nb1 = document["number-1"].value or 0
nb2 = document["number-2"].value or 0
res = double_first_and_add(nb1, nb2)
document["result"].innerHTML = f"Result: ({nb1} * 2) + {nb2} = {res}"
document["submit"].bind("click", add_numbers)
window.WebAssembly.instantiateStreaming(window.fetch("op.wasm")).then(
add_rust_fn
)