Python을 이용해 웹 브라우저에서 동작하는 간단한 애플리케이션을 만드는 방법에 대해 알아보자.
PyScript 소개
PyScript는 HTML 인터페이스와 Pyodide, WASM 및 최신 웹 기술을 사용하여 웹 브라우저에서 동작하는 다양한 Python 애플리케이션을 만들 수 있는 프레임워크이다.PyScript는 Python을 이용해 웹 브라우저에서 동작하는 완성도 높은 애플리케이션을 만들 수 있도록, 여러 공개된 기술을 프레임워크와 결합하는 것을 목표로 하는 메타 프로젝트이다. 브라우저에서 DOM이 작동하는 방식을 원활하게 통합하는 동시에 웹 개발자와 파이썬 개발자 모두에게 자연스러운 파이썬 로직을 추가할 수 있도록 한다. 쉽게 말하자면, Python으로 작성된 로직을 서버 사이드에서 실행하여 결과를 웹 브라우저에서 확인하는 것이 아니라 클라이언트 사이드에서 직접 Python으로 작성된 로직을 실행하도록 한다는 것이 주요 특징이다. 그래도 어렵다면 HTML 파일을 하나 만들고 실제로 PyScript를 이용해 어떻게 Python 로직을 웹 브라우저에서 실행시킬 수 있는지 직접 확인해보자.
PyScript 사용법
PyScript를 사용하려면 적절한 PyScript 파일들을 HTML 파일의 head 태그에 아래와 같이 추가해줘야 한다.
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
그럼 이제 HTML 페이지에서 PyScript 컴포넌트를 사용할 수 있다. PyScript는 현재 다음 요소를 구현하고 있다.
<py-script>
: 웹 페이지 내에서 실행 가능한 Python 코드를 정의하는 데 사용됨. 요소 자체는 페이지에 렌더링되지 않으며 논리를 추가하는 데만 사용됨.<py-repl>
: 웹 페이지에 코드 편집기로 렌더링됨. 사용자가 실행 코드를 작성할 수 있도록 하는 REPL 구성 요소를 생성함.
Chrome과 VSCode 설치하기
PyScript를 본격적으로 다뤄보기 전 크롬 웹 브라우저와 VSCode를 준비한다. VSCode 확장 기능으로 Live Server Extension도 함께 설치해준다.
- Chrome: 웹 브라우저
- VSCode: 코드 편집기
- Live Server Extension: VSCode 확장 기능으로 작성한 페이지를 확인할 수 있다.
py-script 태그 사용하기
py-script 태그 안에 Python 스크립트를 작성하면 웹 페이지에서 스크립트 실행 결과를 확인해볼 수 있다. 몇 가지 예제를 살펴보자.
Hello, World! 출력하기
VSCode를 열고 적당한 폴더를 하나 만든다. 이 경로에 hello.html
파일도 하나 만든 뒤, 아래와 같이 페이지에서 Hello, World!를 출력하는 스크립트를 작성해준다. body 태그 안에 py-script 태그를 작성하고 여기에 Python print 함수 로직을 적는다.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<py-script> print('Hello, World!') </py-script>
</body>
</html>
이 파일을 직접 열거나 VSCode에서 ALT
+ L
, O
를 눌러 파일을 열 수도 있다. 그럼 아래와 같이 웹 브라우저에 ‘Hello, World!’가 출력되는 것을 확인할 수 있다.
π 연산 결과 출력하기
단순히 문자열만 출력하는 것이 아니라 Python으로 연산한 값도 출력할 수 있는지 확인해보자. 이번에는 pi.html
파일을 만들고 위에서 사용한 방법과 같이 py-script 태그 안에 π를 연산하는 로직을 작성해보자.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<py-script>
print("π 연산 결과:")
def compute_pi(n):
pi = 2
for i in range(1,n):
pi *= 4 * i ** 2 / (4 * i ** 2 - 1)
return pi
pi = compute_pi(100000)
s = f"π 연산 결과는 {pi:.3f} 입니다."
print(s)
</py-script>
</body>
</html>
레이블이 지정된 요소에 쓰기
이번에는 페이지의 레이블이 지정된 요소에 문자열을 보내는 pyscript
의 .write()
메서드를 사용해보자. pi.html
파일을 아래와 같이 수정해보자. datetime
을 이용해 만든 날짜 값은 id가 ‘today’인 태그로 보내고, 위에서 만든 pi 연산 결과값은 id가 ‘pi’인 태그로 보내는 스크립트이다.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<b><p>Today is <u><label id='today'></label></u></p></b>
<br>
<div id="pi" class="alert alert-primary"></div>
<py-script>
import datetime as dt
pyscript.write('today', dt.date.today().strftime('%A %B %d, %Y'))
def compute_pi(n):
pi = 2
for i in range(1,n):
pi *= 4 * i ** 2 / (4 * i ** 2 - 1)
return pi
pi = compute_pi(100000)
pyscript.write('pi', f"π 연산 결과는 {pi:.3f} 입니다.")
</py-script>
</body>
</html>
py-config 태그 사용하기
py-config 태그를 사용하여 PyScript 애플리케이션에 대한 종속성 선언과 함께 일반적인 메타 데이터를 설정할 수 있다. 설정은 TOML 혹은 JSON 형식으로 작성해야 한다. JSON 형식이 낯설다면 여기, TOML 형식에 대한 설명은 여기를 참고하면 된다. 여기서는 JSON 형식에 대해서만 살펴보기로 한다.
인라인으로 설정하기
py-config 태그는 보통 head 태그 안에 아래와 같이 작성한다.
<py-config type="json">
{
"autoclose_loader": true,
"runtimes": [{
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
"name": "pyodide-0.21.2",
"lang": "python"
}]
}
</py-config>
src 속성을 이용해 설정하기
설정을 src 속성을 사용해서 아래와 같이 전달할 수도 있다.
<py-config type="json" src="./custom.json"></py-config>
src 속성에서 참조한 ./custom.json
파일은 아래와 같이 작성하면 된다.
{
"autoclose_loader": true,
"runtimes": [{
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
"name": "pyodide-0.21.2",
"lang": "python"
}]
}
인라인 및 src 속성 모두 사용해 설정하기
혹은 설정을 태그 안에도 작성하고, src 속성에도 동시에 작성할 수도 있다.
<py-config type="json" src="./custom.json">
{
"paths": ["./utils.py"]
}
</py-config>
써드파티 OSS 패키지 접근을 위한 종속성 선언하기
PyScript에서 지원하는 많은 써드파티 OSS 패키지에 접근하기 위해 종속성을 선언할 수도 있다. toga 예제와 같이 디스크에 있는 .whl
파일에 직접 연결할 수도 있다.
<py-config type="json">
{
"packages": ["./static/wheels/travertino-0.1.3-py3-none-any.whl"]
}
</py-config>
.whl
이 순수 Python wheel이 아니라면, pyodide에 PR이나 이슈를 열어 여기에 추가하면 된다. 충분한 수요가 있다면, pyodide 팀이 패키지를 추가해줄 수도 있다. PR 후 팀과 상의하는 절차를 거친다면 더 빨리 일이 진행될 수 있다고 한다.
NumPy, Matplotlib 패키지 사용하기
한편 NumPy와 Matplotlib 패키지를 PyScript에서 지원하고 있다. <py-script output="plot">
처럼 사용할 수 있는데, 이는 스크립트의 마지막 줄에 있는 표현식을 가져와서 pyscript.write('plot', fig)
를 실행하는 역할을 한다.
plot.html
파일을 만들고, 아래 스크립트를 입력해보자. NumPy를 이용해 난수를 생성하고 이 값들을 Matplotlib을 통해 시각화한 결과 이미지를 웹 브라우저 상에 출력해줄 수 있다.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<py-config type="json">
{
"packages": ["numpy", "matplotlib"]
}
</py-config>
</head>
<body>
<h1>Let's plot random numbers</h1>
<div id="plot"></div>
<py-script output="plot">
import matplotlib.pyplot as plt
import numpy as np
x = np.random.randn(1000)
y = np.random.randn(1000)
fig, ax = plt.subplots()
ax.scatter(x, y)
fig
</py-script>
</body>
</html>
로컬 모듈 사용하기
패키지 외에도 py-script 태그로 가져올 로컬 Python 모듈을 선언할 수 있다. 예를 들어, data.py
라는 Python 파일에 난수를 생성해주는 함수 make_x_and_y()
를 다음과 같이 정의할 수 있다.
# data.py
import numpy as np
def make_x_and_y(n):
x = np.random.randn(n)
y = np.random.randn(n)
return x, y
HTML py-config 태그에 로컬 모듈에 대한 경로를 설정할 수 있다. plot.html
파일을 아래와 같이 수정해보자.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<py-config type="json">
{
"packages": ["numpy", "matplotlib"],
"paths": ["./data.py"]
}
</py-config>
</head>
<body>
<h1>Let's plot random numbers</h1>
<div id="plot"></div>
<py-script output="plot">
import matplotlib.pyplot as plt
from data import make_x_and_y
x, y = make_x_and_y(n=1000)
fig, ax = plt.subplots()
ax.scatter(x, y)
fig
</py-script>
</body>
</html>
py-config에서 지원하는 선택 값 목록
값 | 유형 | 설명 |
---|---|---|
name |
string | 사용자 응용 프로그램의 이름입니다. 이 필드는 임의의 문자열일 수 있으며 응용프로그램 작성자가 사용자 정의 목적으로 사용합니다. |
description |
string | 사용자 응용 프로그램에 대한 설명입니다. 이 필드는 임의의 문자열일 수 있으며 응용프로그램 작성자가 사용자 정의 목적으로 사용합니다. |
version |
string | 사용자 응용 프로그램의 버전입니다. 이 필드는 임의의 문자열일 수 있으며 응용프로그램 작성자가 사용자 정의 목적으로 사용합니다. PyScript 버전과 관련이 없습니다. |
schema_version |
number | 지원되는 모든 키를 결정하는 구성 스키마의 버전입니다. 이것은 사용자가 제공할 수 있으므로 PyScript는 구성에서 무엇을 기대해야 하는지 알 수 있습니다. 제공하지 않으면 스키마의 최신 버전이 자동으로 사용됩니다. |
type |
string | 프로젝트 유형입니다. 기본값은 “앱”, 즉 사용자 애플리케이션입니다. |
author_name |
string | 저자의 이름입니다. |
author_email |
string | 저자의 이메일. |
license |
string | 사용자 애플리케이션에 사용할 라이선스입니다. |
autoclose_loader |
boolean | False인 경우 PyScript는 시작 작업이 완료될 때 로딩 시작 화면을 닫지 않습니다. |
packages |
List of Packages | 써드파티 OSS 패키지에 대한 종속성이 여기에 지정됩니다. 기본값은 빈 목록입니다. |
paths |
List of Paths | 로컬 Python 모듈은 여기에서 지정해야 합니다. 기본값은 빈 목록입니다. |
plugins |
List of Plugins | 플러그인 목록은 여기에서 지정해야 합니다. 기본값은 빈 목록입니다. |
runtimes |
List of Runtimes | 아래에 설명된 런타임 구성 목록입니다. 기본값은 단일 Pyodide 기반 런타임을 포함합니다. |
runtime 설정 구성 목록
값 | 유형 | 설명 |
---|---|---|
src |
string (Required) | 런타임 소스에 대한 URL입니다. |
name |
string | 런타임의 이름입니다. 이 필드는 임의의 문자열일 수 있으며 애플리케이션 작성자가 고유한 사용자 정의 목적으로 사용합니다. |
lang |
string | 런타임에서 지원하는 프로그래밍 언어입니다. 이 필드는 응용 프로그램 작성자가 설명을 제공하는 데 사용할 수 있습니다. 현재 PyScript가 작동하는 방식에 영향을 미치지 않습니다. |
추가 정보 설정 방법
위 방식 외에도 메타데이터 정보와 관련이 있거나 애플리케이션 내에서 사용 중인 추가적인 키와 값을 설정할 수 있다.
<py-config type="json">
{
"magic": "unicorn"
}
</py-config>
py-repl 태그 사용하기
py-repl 태그는 페이지에 코드 편집기로 렌더링되는 REPL 컴포넌트를 생성하여 실행 가능한 코드를 인라인으로 작성할 수 있도록 해준다. repl.html
을 만들어 다음을 작성해보자.
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<py-repl></py-repl>
</html>
이 파일을 웹 브라우저에서 실행하면 아래 이미지와 같이 코드 편집기가 렌더링되는데, 이 곳에 Python 명령을 입력하고 실행해볼 수 있다.
시각적 컴포넌트 태그
아래 태그들을 사용하여 HTML 페이지에 시각적 속성을 추가할 수도 있다.
태그 | 설명 |
---|---|
<py-inputbox> |
사용자에게 입력 값을 입력하라는 메시지를 표시하는 데 사용할 수 있는 입력 상자를 추가합니다. |
<py-box> |
<py-box> 의 요소가 페이지에 정렬되고 표시되어야 하는 방법을 정의하는 하나 이상의 시각적 구성 요소를 호스팅하는 데 사용할 수 있는 컨테이너 개체를 만듭니다. |
<py-button> |
작성자가 ‘on_focus’ 또는 ‘on_click’과 같은 버튼에 대한 작업에 대한 레이블 및 이벤트 핸들러를 추가할 수 있는 버튼을 추가합니다. |
<py-title> |
태그 내부의 텍스트를 페이지 제목으로 스타일 지정하는 정적 텍스트 제목 구성 요소를 추가합니다. |
댓글남기기