Python을 이용해 웹 브라우저에서 동작하는 간단한 애플리케이션을 만드는 방법에 대해 알아보자.


PyScript 소개

PNG

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도 함께 설치해준다.


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!’가 출력되는 것을 확인할 수 있다.

PNG


π 연산 결과 출력하기

단순히 문자열만 출력하는 것이 아니라 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>

PNG


레이블이 지정된 요소에 쓰기

이번에는 페이지의 레이블이 지정된 요소에 문자열을 보내는 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>

PNG


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>

PNG


로컬 모듈 사용하기

패키지 외에도 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>

PNG


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 명령을 입력하고 실행해볼 수 있다.

PNG


시각적 컴포넌트 태그

아래 태그들을 사용하여 HTML 페이지에 시각적 속성을 추가할 수도 있다.

태그 설명
<py-inputbox> 사용자에게 입력 값을 입력하라는 메시지를 표시하는 데 사용할 수 있는 입력 상자를 추가합니다.
<py-box> <py-box>의 요소가 페이지에 정렬되고 표시되어야 하는 방법을 정의하는 하나 이상의 시각적 구성 요소를 호스팅하는 데 사용할 수 있는 컨테이너 개체를 만듭니다.
<py-button> 작성자가 ‘on_focus’ 또는 ‘on_click’과 같은 버튼에 대한 작업에 대한 레이블 및 이벤트 핸들러를 추가할 수 있는 버튼을 추가합니다.
<py-title> 태그 내부의 텍스트를 페이지 제목으로 스타일 지정하는 정적 텍스트 제목 구성 요소를 추가합니다.


참고

태그:

카테고리:

업데이트:

댓글남기기