Introducing PyWebIO: Build Web Frontends with Pure Python
This article introduces the PyWebIO library, explains how to install it, showcases its output and input functions, and provides several practical example programs—including a BMI calculator, a markdown editor, a chat room, and a Gomoku game—demonstrating how Python can be used to create interactive web front‑ends without writing HTML or JavaScript.
While browsing GitHub, the author discovered PyWebIO, a Python third‑party library that enables developers to create web pages using only Python and supports popular web frameworks such as Flask, Django, and Tornado.
PyWebIO also supports data‑visualization charts and provides a one‑line function to render Markdown text.
Installation can be performed via the command line:
<code>pip install pywebio</code>If the default source is slow, a domestic mirror can be used:
<code>pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pywebio</code>PyWebIO offers several output functions, including:
put_text() – output plain text
put_table() – output tables
put_markdown() – render Markdown content
put_file() – provide file download links
put_image() – display images
put_button() – create buttons
It also provides an input function similar to Python’s built‑in input() :
<code>from pywebio.input import *
def main():
name = input("请输入你的名字:")
if __name__ == '__main__':
main()</code>Several example programs are presented to illustrate PyWebIO’s capabilities:
1. BMI Calculator
<code>from pywebio.input import input, FLOAT
from pywebio.output import put_text
def bmi():
height = input("Your Height(cm):", type=FLOAT)
weight = input("Your Weight(kg):", type=FLOAT)
BMI = weight / (height / 100) ** 2
top_status = [(14.9, 'Severely underweight'), (18.4, 'Underweight'),
(22.9, 'Normal'), (27.5, 'Overweight'),
(40.0, 'Moderately obese'), (float('inf'), 'Severely obese')]
for top, status in top_status:
if BMI <= top:
put_text('Your BMI: %.1f, category: %s' % (BMI, status))
break
if __name__ == '__main__':
bmi()</code>2. Markdown Editor
<code>from pywebio import start_server
from pywebio.output import *
from pywebio.pin import *
from pywebio.session import set_env, download
def main():
"""Markdown Previewer"""
set_env(output_animation=False)
put_markdown("""# Markdown Live Preview
The online markdown editor with live preview. ...""")
put_textarea('md_text', rows=18, code={'mode': 'markdown'})
put_buttons(['Download content'], lambda _: download('saved.md', pin.md_text.encode('utf8')), small=True)
put_markdown('## Preview')
while True:
change_detail = pin_wait_change('md_text')
with use_scope('md', clear=True):
put_markdown(change_detail['value'], sanitize=False)
if __name__ == '__main__':
start_server(main, port=8080, debug=True)</code>3. Chat Room
<code>import asyncio
from pywebio import start_server
from pywebio.input import *
from pywebio.output import *
from pywebio.session import defer_call, info as session_info, run_async
MAX_MESSAGES_CNT = 10 ** 4
chat_msgs = []
online_users = set()
def t(eng, chinese):
return chinese if 'zh' in session_info.user_language else eng
async def refresh_msg(my_name):
global chat_msgs
last_idx = len(chat_msgs)
while True:
await asyncio.sleep(0.5)
for m in chat_msgs[last_idx:]:
if m[0] != my_name:
put_markdown('`%s`: %s' % m, sanitize=True, scope='msg-box')
if len(chat_msgs) > MAX_MESSAGES_CNT:
chat_msgs = chat_msgs[len(chat_msgs)//2:]
last_idx = len(chat_msgs)
async def main():
global chat_msgs
put_markdown(t("## PyWebIO chat room\nWelcome...", "## PyWebIO聊天室\n欢迎..."))
put_scrollable(put_scope('msg-box'), height=300, keep_bottom=True)
nickname = await input(t('Your nickname', '请输入你的昵称'), required=True,
validate=lambda n: t('This name is already been used','昵称已被使用') if n in online_users else None)
online_users.add(nickname)
chat_msgs.append(('📢', '`%s` joins the room. %s users online' % (nickname, len(online_users))))
@defer_call
def on_close():
online_users.remove(nickname)
chat_msgs.append(('📢', '`%s` leaves the room. %s users online' % (nickname, len(online_users))))
refresh_task = run_async(refresh_msg(nickname))
while True:
data = await input_group(t('Send message','发送消息'), [
input(name='msg', help_text=t('Message content supports inline Markdown syntax','消息内容支持行内Markdown语法')),
actions(name='cmd', buttons=[t('Send','发送'), t('Multiline Input','多行输入'), {'label': t('Exit','退出'), 'type':'cancel'}])
], validate=lambda d: ('msg','Message content cannot be empty') if d['cmd']==t('Send','发送') and not d['msg'] else None)
if data is None:
break
if data['cmd']==t('Multiline Input','多行输入'):
data['msg']='\n'+await textarea('Message content', help_text=t('Message content supports Markdown syntax','消息内容支持Markdown语法'))
put_markdown('`%s`: %s' % (nickname, data['msg']), sanitize=True, scope='msg-box')
chat_msgs.append((nickname, data['msg']))
refresh_task.close()
toast('You have left the chat room')
if __name__ == '__main__':
start_server(main, debug=True)</code>4. Gomoku (Five‑in‑a‑Row) Game
<code>import time
from pywebio import session, start_server
from pywebio.output import *
goboard_size = 15
goboard = [[-1]*goboard_size for _ in range(goboard_size)]
# ... (game logic omitted for brevity) ...
if __name__ == '__main__':
start_server(main, debug=True, port=8080)</code>The author concludes that after a brief trial, PyWebIO feels powerful, supports various chart styles, integrates with web frameworks, and enables developers to display Python programs on web pages, effectively allowing Python to be used for front‑end development.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.