PyWebIO

PyWebIO提供了一系列命令式的交互函数来在浏览器上获取用户输入和进行输出,将浏览器变成了一个“富文本终端”,可以用于构建简单的Web应用或基于浏览器的GUI应用。 使用PyWebIO,开发者能像编写终端脚本一样(基于input和print进行交互)来编写应用,无需具备HTML和JS的相关知识; PyWebIO还可以方便地整合进现有的Web服务。非常适合快速构建对UI要求不高的应用。

特性

  • 使用同步而不是基于回调的方式获取输入,代码编写逻辑更自然

  • 非声明式布局,布局方式简单高效

  • 代码侵入性小,旧脚本代码仅需修改输入输出逻辑便可改造为Web服务

  • 支持整合到现有的Web服务,目前支持与Flask、Django、Tornado、aiohttp、 FastAPI(Starlette)框架集成

  • 同时支持基于线程的执行模型和基于协程的执行模型

  • 支持结合第三方库实现数据可视化

Installation

稳定版:

pip3 install -U pywebio

开发版:

pip3 install -U https://github.com/pywebio/PyWebIO/archive/dev-release.zip

系统要求: PyWebIO要求 Python 版本在 3.5.2 及以上

Hello, world

这是一个使用PyWebIO计算 BMI指数 的脚本:

from pywebio.input import input, FLOAT
from pywebio.output import put_text

def bmi():
    height = input("请输入你的身高(cm):", type=FLOAT)
    weight = input("请输入你的体重(kg):", type=FLOAT)

    BMI = weight / (height / 100) ** 2

    top_status = [(14.9, '极瘦'), (18.4, '偏瘦'),
                  (22.9, '正常'), (27.5, '过重'),
                  (40.0, '肥胖'), (float('inf'), '非常肥胖')]

    for top, status in top_status:
        if BMI <= top:
            put_text('你的 BMI 值: %.1f,身体状态:%s' % (BMI, status))
            break

if __name__ == '__main__':
    bmi()

如果没有使用PyWebIO,这只是一个非常简单的脚本,而通过使用PyWebIO提供的输入输出函数,你可以在浏览器中与代码进行交互:

_images/demo.gif

将上面代码最后一行对 bmi() 的直接调用改为使用 pywebio.start_server(bmi, port=80) 便可以在80端口提供 bmi() 服务( 在线Demo )。

bmi() 服务整合到现有的Web框架请参考 与Web框架集成

Documentation

这个文档同时也提供 PDF 和 Epub 格式.

User’s guide

如果你接触过Web开发,你可能对接下来描述的PyWebIO的用法感到不太习惯,不同于传统Web开发的后端实现接口、前端进行展示交互的模式,在PyWebIO中,所有的逻辑都通过编写Python代码实现。

你可以按照编写控制台程序的逻辑编写PyWebIO应用,只不过这里的终端变成了浏览器。通过PyWebIO提供的命令式API,你可以简单地调用 put_text()put_image()put_table() 等函数输出文本、图片、表格等内容到浏览器,也可以调用 input()select()file_upload() 等函数在浏览器上显示不同表单来接收用户的输入。此外PyWebIO中还提供了点击事件、布局等支持,让你可以使用最少的代码完成与用户的交互,并尽可能提供良好的用户体验。

This user guide introduces you the most of the features of PyWebIO. There is a demo link at the top right of the example codes in this document, where you can run the example code online and see what happens. Also, the PyWebIO Playground is a good place to write, run and share your PyWebIO code online.

输入

输入函数都定义在 pywebio.input 模块中,可以使用 from pywebio.input import * 引入。

调用输入函数会在浏览器上弹出一个输入表单来获取输入。PyWebIO的输入函数是阻塞式的(和Python内置的 input 一样),在表单被成功提交之前,输入函数不会返回。

基本输入

首先是一些基本类型的输入。

文本输入:

age = input("How old are you?", type=NUMBER)

这样一行代码的效果为:浏览器会弹出一个文本输入框来获取输入,在用户完成输入将表单提交后,函数返回用户输入的值。

下面是一些其他类型的输入函数:

# Password input
password = input("Input password", type=PASSWORD)

# Drop-down selection
gift = select('Which gift you want?', ['keyboard', 'ipad'])

# Checkbox
agree = checkbox("User Term", options=['I agree to terms and conditions'])

# Single choice
answer = radio("Choose one", options=['A', 'B', 'C', 'D'])

# Multi-line text input
text = textarea('Text Area', rows=3, placeholder='Some text')

# File Upload
img = file_upload("Select a image:", accept="image/*")
输入选项

输入函数可指定的参数非常丰富(全部参数及含义请见 函数文档 ):

input('This is label', type=TEXT, placeholder='This is placeholder',
        help_text='This is help text', required=True)

以上代码将在浏览器上显示如下:

_images/input_1.png

我们可以为输入指定校验函数,校验函数应在校验通过时返回None,否则返回错误消息:

def check_age(p):  # return None when the check passes, otherwise return the error message
    if p < 10:
        return 'Too young!!'
    if p > 60:
        return 'Too old!!'

age = input("How old are you?", type=NUMBER, validate=check_age)

当用户输入了不合法的值时,页面上的显示如下:

_images/input_2.png

pywebio.input.textarea() 中可以使用 code 参数来开启代码风格的编辑区。

code = textarea('Code Edit', code={
    'mode': "python",
    'theme': 'darcula',
}, value='import something\n# Write your python code')

以上代码将在浏览器上显示如下:

_images/codemirror_textarea.png
输入组

PyWebIO支持输入组, 返回结果为一个字典。pywebio.input.input_group() 接受单项输入组成的列表作为参数, 返回以单项输入中的 name 作为键、以输入数据为值的字典:

data = input_group("Basic info",[
  input('Input your name', name='name'),
  input('Input your age', name='age', type=NUMBER, validate=check_age)
])
put_text(data['name'], data['age'])

输入组中同样支持使用 validate 参数设置校验函数,其接受整个表单数据作为参数:

def check_form(data):  # return (input name, error msg) when validation fail
    if len(data['name']) > 6:
        return ('name', 'Name too long!')
    if data['age'] <= 0:
        return ('age', 'Age can not be negative!')

注意

PyWebIO 根据是否在输入函数中传入 name 参数来判断输入函数是在 input_group() 中还是被单独调用。所以当单独调用一个输入函数时, 不要 设置 name 参数;而在 input_group() 中调用输入函数时,需 务必提供 name 参数。

输出

输出函数都定义在 pywebio.output 模块中,可以使用 from pywebio.output import * 引入。

调用输出函数后,内容会实时输出到浏览器,在应用的生命周期内,可以在任意时刻调用输出函数。

基本输出

PyWebIO提供了一系列函数来输出文本、表格、图像等格式:

# Text Output
put_text("Hello world!")

# Table Output
put_table([
    ['Commodity', 'Price'],
    ['Apple', '5.5'],
    ['Banana', '7'],
])

# Image Output
put_image(open('/path/to/some/image.png', 'rb').read())  # local image 
put_image('http://example.com/some-image.png')  # internet image 

# Markdown Output
put_markdown('~~Strikethrough~~')

# File Output
put_file('hello_word.txt', b'hello word!')

# Show a PopUp
popup('popup title', 'popup text content')

# Show a notification message
toast('New message 🔔')

PyWebIO提供的全部输出函数见 pywebio.output 模块。另外,PyWebIO还支持一些第三方库来进行数据可视化,参见 第三方库生态

注解

如果你在Python shell, IPython 或 jupyter notebook这种交互式执行环境中使用PyWebIO,你需要显式调用 show() 方法来显示输出:

>>> put_text("Hello world!").show()
>>> put_table([
...     ['A', 'B'],
...     [put_markdown(...), put_text('C')]
... ]).show()
组合输出

函数名以 put_ 开始的输出函数,可以与一些输出函数组合使用,作为最终输出的一部分:

put_table() 支持以 put_xxx() 调用作为单元格内容:

put_table([
    ['Type', 'Content'],
    ['html', put_html('X<sup>2</sup>')],
    ['text', '<hr/>'],  # equal to ['text', put_text('<hr/>')]
    ['buttons', put_buttons(['A', 'B'], onclick=...)],  
    ['markdown', put_markdown('`Awesome PyWebIO!`')],
    ['file', put_file('hello.text', b'hello world')],
    ['table', put_table([['A', 'B'], ['C', 'D']])]
])

以上代码将在浏览器上显示如下:

_images/put_table.png

类似地, popup() 也可以将 put_xxx() 调用作为弹窗内容:

popup('Popup title', [
    put_html('<h3>Popup Content</h3>'),
    'plain html: <br/>',  # Equivalent to: put_text('plain html: <br/>')
    put_table([['A', 'B'], ['C', 'D']]),
    put_button('close_popup()', onclick=close_popup)
])

另外,你可以使用 put_widget() 来创建可以接受 put_xxx() 的自定义输出控件。

接受 put_xxx() 调用作为参数的完整输出函数清单请见 输出函数列表

上下文管理器

一些接受 put_xxx() 调用作为参数的输出函数支持作为上下文管理器来使用:

with put_collapse('This is title'):
    for i in range(4):
        put_text(i)

    put_table([
        ['Commodity', 'Price'],
        ['Apple', '5.5'],
        ['Banana', '7'],
    ])

支持上下文管理器的完整函数清单请见 输出函数列表

事件回调

从上面可以看出,PyWebIO把交互分成了输入和输出两部分:输入函数为阻塞式调用,会在用户浏览器上显示一个表单,在用户提交表单之前输入函数将不会返回;输出函数将内容实时输出至浏览器。这种交互方式和控制台程序是一致的,因此PyWebIO应用非常适合使用控制台程序的编写逻辑来进行开发。

此外,PyWebIO还支持事件回调:PyWebIO允许你输出一些控件并绑定回调函数,当控件被点击时相应的回调函数便会被执行。

下面是一个例子:

from functools import partial

def edit_row(choice, row):
    put_text("You click %s button ar row %s" % (choice, row))

put_table([
    ['Idx', 'Actions'],
    [1, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=1))],
    [2, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=2))],
    [3, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=3))],
])

put_table() 的调用不会阻塞。当用户点击了某行中的按钮时,PyWebIO会自动调用相应的回调函数:

_images/table_onclick.gif

当然,PyWebIO还支持单独的按钮控件:

def btn_click(btn_val):
    put_text("You click %s button" % btn_val)

put_buttons(['A', 'B', 'C'], onclick=btn_click)  # a group of buttons

put_button("Click me", onclick=lambda: toast("Clicked"))  # single button

事实上,不仅是按钮,所有的输出都可以绑定点击事件。你可以在输出函数之后调用 onclick() 方法来绑定点击事件:

put_image('some-image.png').onclick(lambda: toast('You click an image'))  

# set onclick in combined output
put_table([
    ['Commodity', 'Price'],
    ['Apple', put_text('5.5').onclick(lambda: toast('You click the text'))],
])

onclick() 方法的返回值为对象本身,所以可以继续用于组合输出中。

输出域Scope

PyWebIO使用scope模型来控制内容输出的位置。scope为输出内容的容器,你可以创建一个scope并将内容输出到其中。

每个输出函数(函数名形如 put_xxx() )都会将内容输出到一个Scope,默认为”当前Scope”,”当前Scope”由 use_scope() 设置。

use_scope()

可以使用 use_scope() 开启并进入一个新的输出域,或进入一个已经存在的输出域:

with use_scope('scope1'):  # 创建并进入scope 'scope1'
    put_text('text1 in scope1')  # 输出内容到 scope1

put_text('text in parent scope of scope1')  # 输出内容到 ROOT scope

with use_scope('scope1'):  # 进入之前创建的scope 'scope1'
    put_text('text2 in scope1')  # 输出内容到 scope1

以上代码将会输出:

text1 in scope1
text2 in scope1
text in parent scope of scope1

use_scope() 还可以使用 clear 参数将scope中原有的内容清空:

with use_scope('scope2'):
    put_text('create scope2')

put_text('text in parent scope of scope2')

with use_scope('scope2', clear=True):  # enter the existing scope and clear the previous content
    put_text('text in scope2')

以上代码将会输出:

text in scope2
text in parent scope of scope2

use_scope() 还可以作为装饰器来使用:

from datetime import datetime

@use_scope('time', clear=True)
def show_time():
    put_text(datetime.now())

第一次调用 show_time 时,将会创建 time 输出域并在其中输出当前时间,之后每次调用 show_time() ,输出域都会被新的内容覆盖。

Scope支持嵌套。会话开始时,PyWebIO应用只有一个 ROOT scope。你可以在一个scope中创建新的scope。比如,以下代码将会创建3个scope:

with use_scope('A'):
    put_text('Text in scope A')

    with use_scope('B'):
        put_text('Text in scope B')

with use_scope('C'):
    put_text('Text in scope C')

以上代码将会产生如下Scope布局:

┌─ROOT────────────────────┐
│                         │
│ ┌─A───────────────────┐ │
│ │ Text in scope A     │ │
│ │ ┌─B───────────────┐ │ │
│ │ │ Text in scope B │ │ │
│ │ └─────────────────┘ │ │
│ └─────────────────────┘ │
│                         │
│ ┌─C───────────────────┐ │
│ │ Text in scope C     │ │
│ └─────────────────────┘ │
└─────────────────────────┘

put_scope()

我们已经知道scope实际上是输出内容的容器,那么我们能否将scope作为输出的子元素呢(比如将scope作为表格的一个cell),答案是肯定的。你可以使用 put_scope() 来显式创建一个scope,而从它以 put_ 开头的函数名可以看出,它也可以被传递到任何可以接受 put_xxx() 调用的地方。

put_table([
    ['Name', 'Hobbies'],
    ['Tom', put_scope('hobby', content=put_text('Coding'))]  # hobby is initialized to coding
])

with use_scope('hobby', clear=True):
    put_text('Movie')  # hobby is reset to Movie

# append Music, Drama to hobby
with use_scope('hobby'):
    put_text('Music')
    put_text('Drama')

# insert the Coding into the top of the hobby
put_markdown('**Coding**', scope='hobby', position=0)

警告

It is not allowed to have two scopes with the same name in the application.

输出域控制函数

除了 use_scope()put_scope() , PyWebIO还提供了以下scope控制函数:

另外,所有的输出函数还支持使用 scope 参数来指定输出的目的scope,也可使用 position 参数来指定在目标scope中输出的位置。更多信息参见 output 模块

布局

通常,使用上述输出函数足以完成大部分输出,但是这些输出之间全都是竖直排列的。如果想创建更复杂的布局,需要使用布局函数。

pywebio.output 模块提供了3个布局函数,通过对他们进行组合可以完成各种复杂的布局:

  • put_row() : 使用行布局输出内容. 内容在水平方向上排列

  • put_column() : 使用列布局输出内容. 内容在竖直方向上排列

  • put_grid() : 使用网格布局输出内容

通过组合 put_row()put_column() 可以实现灵活布局:

put_row([
    put_column([
        put_code('A'),
        put_row([
            put_code('B1'), None,  # None represents the space between the output
            put_code('B2'), None,
            put_code('B3'),
        ]),
        put_code('C'),
    ]), None,
    put_code('D'), None,
    put_code('E')
])

以上代码将在浏览器上显示如下:

_images/layout.png

布局函数还支持自定义各部分的尺寸:

put_row([put_image(…), put_image(…)], size='40% 60%')  # 左右两图宽度比2:3

更多布局函数的用法及代码示例请查阅 布局函数文档 .

样式

如果你熟悉 CSS样式 ,你还可以在输出函数后调用 style() 方法给输出设定自定义样式。

可以给单个的 put_xxx() 输出设定CSS样式,也可以配合组合输出使用:

put_text('hello').style('color: red; font-size: 20px')

# in combined output
put_row([
    put_text('hello').style('color: red'),
    put_markdown('markdown')
]).style('margin-top: 20px')

style() 方法的返回值为对象本身,所以可以继续用于组合输出中。

Run application

在PyWebIO中,有两种方式用来运行PyWebIO应用:作为脚本运行和使用 pywebio.start_server()pywebio.platform.path_deploy() 来作为Web服务运行。

Overview

Server模式

在Server模式下,PyWebIO会启动一个Web服务来持续性地提供服务。当用户访问服务地址时,PyWebIO会开启一个新会话并运行PyWebIO应用。

将PyWebIO应用部署为web服务的最常用方式是使用 start_server()

from pywebio import *

def main():  # PyWebIO application function
    name = input.input("what's your name")
    output.put_text("hello", name)

start_server(main, port=8080, debug=True)

现在,在 http://127.0.0.1:8080/ 页面就会看到欢迎页面了。

使用 debug=True 来开启debug模式,这时server会在检测到代码发生更改后进行重启。

start_server() 提供了对远程访问的支持,当开启远程访问后(通过在 start_server() 中传入 remote_access=True 开启 ),你将会得到一个用于访问当前应用的临时的公网访问地址,其他任何人都可以使用此地址访问你的应用。远程接入可以很方便地将应用临时分享给其他人。

将PyWebIO应用部署为web服务的另一种方式是使用 path_deploy()path_deploy() 可以从一个目录中部署PyWebIO应用,只需要在该目录下的python文件中定义PyWebIO应用,就可以通过URL中的路径来访问这些应用了。

注意

注意,在Server模式下, pywebio.inputpywebio.outputpywebio.session 模块内的函数仅能在任务函数上下文中进行调用。比如如下调用是 不被允许的

import pywebio
from pywebio.input import input

port = input('Input port number:')   # ❌ error
pywebio.start_server(my_task_func, port=int(port))

Script模式

如果你在代码中没有调用 start_server()path_deploy() 函数,那么你就是以脚本模式在运行PyWebIO应用。

在脚本模式中,当首次运行到对PyWebIO交互函数的调用时,会自动打开浏览器的一个页面,后续的PyWebIO交互都会在这个页面上进行。当脚本运行结束,这个页面也将不再有效。

如果用户在脚本结束运行之前关闭了浏览器,那么之后会话内对于PyWebIO交互函数的调用将会引发一个 SessionException 异常。

并发

PyWebIO 支持在多线程环境中使用。

Script模式

在 Script模式下,你可以自由地启动线程,并在其中调用PyWebIO的交互函数。当所有非 Daemon线程 运行结束后,脚本退出。

Server模式

Server模式下,如果需要在新创建的线程中使用PyWebIO的交互函数,需要手动调用 register_thread(thread) 对新进程进行注册(这样PyWebIO才能知道新创建的线程属于哪个会话)。如果新创建的线程中没有使用到PyWebIO的交互函数,则无需注册。没有使用 register_thread(thread) 注册的线程不受会话管理,其调用PyWebIO的交互函数将会产生 SessionNotFoundException 异常。

Server模式下多线程的使用示例:

def show_time():
    while True:
        with use_scope(name='time', clear=True):
            put_text(datetime.datetime.now())
            time.sleep(1)

def app():
    t = threading.Thread(target=show_time)
    register_thread(t)
    put_markdown('## Clock')
    t.start()  # run `show_time()` in background

    # ❌ this thread will cause `SessionNotFoundException`
    threading.Thread(target=show_time).start()

    put_text('Background task started.')


start_server(app, port=8080, debug=True)
会话的结束

当用户关闭浏览器页面时,与之相应的会话也将被关闭。会话关闭后,应用中未返回的PyWebIO输入函数的调用将会抛出 SessionClosedException 异常,后续对PyWebIO交互函数的调用将会引发 SessionNotFoundExceptionSessionClosedException 异常。

大部分情况下,你不需要捕获这些异常,让这些异常来终止代码的执行通常是比较合适的。

可以使用 pywebio.session.defer_call(func) 来设置会话结束时需要调用的函数。无论是因为用户主动关闭页面还是任务结束使得会话关闭,设置的函数都会被执行。defer_call(func) 可以用于资源清理等工作。在会话中可以多次调用 defer_call() ,会话结束后将会顺序执行设置的函数。

More about PyWebIO

目前为止,你已经了解了PyWebIO中最重要的特性,并且可以开始编写PyWebIO应用了。然而,有些功能前面我们并没有覆盖到,这里提供了对剩余特性的一些简短介绍,如果你在应用编写过程中需要用到这里的某个特性,你可以查阅对应的详细文档。

另外,你可以在 cookbook 页面找到一些对于编写PyWebIO应用很有帮助的代码片段。

session 模块

pywebio.session 模块提供了对会话的更多控制 。

  • 使用 set_env() 来为当前会话设置标题、页面外观、输入栏等内容。

  • info 对象提供了关于当前绘画的很多信息,比如用户IP地址、用户语言、用户浏览器信息等。

  • local 是一个session-local的存储对象, 用于存储会话独立的数据。

  • run_js() 让你在用户浏览器中执行JavaScript代码, eval_js() 让你执行并获取JavaScript表达式的值。

pin 模块

你已经知道,PyWebIO的输入函数是阻塞式的,并且输入表单会在成功提交后消失。在某些时候,你可能想要输入表单一直显示并可以持续性接收用户输入,这时你可以使用 pywebio.pin 模块。

platform 模块

pywebio.platform 模块提供了将PyWebIO应用以多种方式部署的支持。

PyWebIO的服务端与浏览器可以通过两种协议(WebSocket 和 HTTP 协议)进行通信,默认使用WebSocket协议,如果你想使用HTTP协议,你可以选择本模块中的其他 start_server() 函数。

如果要为PyWebIO应用设置一些网页相关的配置,可以尝试使用 pywebio.config()

高级特性

可以将PyWebIO应用整合到现存的Python Web项目中,PyWebIO应用和web项目使用一个web框架。详细信息参见 Advanced Topic: Integration with Web Framework

PyWebIO还支持基于协程的会话。具体参见 Advanced Topic: Coroutine-based session

如果你想要将PyWebIO应用打包到一个单独的可执行文件里面,从而使用户可以在没有安装python解释器的情况下运行应用,你可以参考 Build stand-alone App

如果你想在PyWebIO应用中进行一些数据可视化,可以参考 Data visualization

Last but not least

以上基本就是PyWebIO的全部功能了,你可以继续阅读接下来的文档,或者立即开始PyWebIO应用的编写了。

最后再提供一条建议,当你在使用PyWebIO遇到设计上的问题时,可以问一下自己:如果在是在终端程序中我会怎么做?如果你已经有答案了,那么在PyWebIO中一样可以使用这样的方式完成。如果问题依然存在或者觉得解决方案不够好,你可以考虑使用 回调机制pin 模块。

OK, Have fun with PyWebIO!

pywebio.input — 输入模块

本模块提供了一系列函数来从浏览器接收用户不同的形式的输入

输入函数大致分为两类,一类是单项输入:

name = input("What's your name")
print("Your name is %s" % name)

另一类是使用 input_group 的输入组:

info = input_group("User info",[
  input('Input your name', name='name'),
  input('Input your age', name='age', type=NUMBER)
])
print(info['name'], info['age'])

输入组中需要在每一项输入函数中提供 name 参数来用于在结果中标识不同输入项.

注解

PyWebIO 根据是否在输入函数中传入 name 参数来判断输入函数是在 input_group 中还是被单独调用。所以当你想要单独调用一个输入函数时,请不要设置 name 参数;而在 input_group 中调用输入函数时,务必提供 name 参数。

输入默认可以为空,如果需要用户必须提供值,则需要在输入函数中传入 required=True (部分输入函数不支持 required 参数)

本模块中的输入函数都是阻塞式的,输入表单会在成功提交后销毁。如果你想让表单可以一直显示在页面上并可以持续性接收输入,你可以考虑使用 pin 模块。

函数清单

函数

简介

input

文本输入

textarea

多行文本输入

select

下拉选择框

checkbox

勾选选项

radio

单选选项

slider

滑块输入

actions

按钮选项

file_upload

文件上传

input_group

输入组

input_update

更新输入项

函数文档

pywebio.input.input(label: str = '', type: str = 'text', *, validate: Optional[Callable[[Any], Optional[str]]] = None, name: Optional[str] = None, value: Optional[Union[str, int]] = None, action: Optional[Tuple[str, Callable[[Callable], None]]] = None, onchange: Optional[Callable[[Any], None]] = None, placeholder: Optional[str] = None, required: Optional[bool] = None, readonly: Optional[bool] = None, datalist: Optional[List[str]] = None, help_text: Optional[str] = None, **other_html_attrs)[源代码]

文本输入

参数
  • label (str) – 输入框标签

  • type (str) –

    Input type. Currently, supported types are:TEXT , NUMBER , FLOAT , PASSWORD , URL , DATE , TIME, DATETIME, COLOR

    The value of DATE , TIME, DATETIME type is a string in the format of YYYY-MM-DD , HH:MM:SS , YYYY-MM-DDTHH:MM respectively (%Y-%m-%d, %H:%M:%S, %Y-%m-%dT%H:%M in python strptime() format).

  • validate (callable) –

    输入值校验函数。 如果提供,当用户输入完毕或提交表单后校验函数将被调用。

    validate receives the input value as a parameter. When the input value is valid, it returns None. When the input value is invalid, it returns an error message string.

    For example:

    def check_age(age):
        if age>30:
            return 'Too old'
        elif age<10:
            return 'Too young'
    input('Input your age', type=NUMBER, validate=check_age)
    

  • name (str) – 输入框的名字。与 input_group 配合使用,用于在输入组的结果中标识不同输入项。 在单个输入中,不可以设置该参数!

  • value (str) – 输入框的初始值

  • action (tuple(label:str, callback:callable)) –

    在输入框右侧显示一个按钮,用户可通过点击按钮为输入框设置值。

    label 为按钮的显示文本, callback 为按钮点击的回调函数。

    回调函数需要接收一个 set_value 位置参数, set_value 是一个可调用对象,接受单参数调用和双参数调用。

    单参数调用时,签名为 set_value(value:str) ,调用set_value即可将表单项的值设置为传入的 value 参数。

    双参数调用时,签名为 set_value(value:any, label:str) ,其中:

    • value 参数为最终输入项的返回值,可以为任意Python对象,并不会传递给用户浏览器

    • label 参数用于显示在用户表单项上

    使用双参数调用 set_value 后,用户表单项会变为只读状态。

    双参数调用的使用场景为:表单项的值通过回调动态生成,同时希望用户表单显示的和实际提交的数据不同(例如表单项上可以显示更人性化的内容,而表单项的值则可以保存更方便被处理的对象)

    使用示例

    import time
    def set_now_ts(set_value):
        set_value(int(time.time()))
    
    ts = input('Timestamp', type=NUMBER, action=('Now', set_now_ts))
    from datetime import date,timedelta
    def select_date(set_value):
        with popup('Select Date'):
            put_buttons(['Today'], onclick=[lambda: set_value(date.today(), 'Today')])
            put_buttons(['Yesterday'], onclick=[lambda: set_value(date.today() - timedelta(days=1), 'Yesterday')])
    
    d = input('Date', action=('Select', select_date), readonly=True)
    put_text(type(d), d)
    

    Note: 当使用 基于协程的会话实现 时,回调函数 callback 可以为协程函数.

  • onchange (callable) –

    A callback function which will be called when user change the value of this input field.

    onchange 回调函数接收一个参数——输入项改变后的值。 onchange 的典型用途是配合 input_update() 来在一个表单中实现相互依赖的输入。

  • placeholder (str) – 输入框的提示内容。提示内容会在输入框未输入值时以浅色字体显示在输入框中

  • required (bool) – 当前输入是否为必填项,默认为 False

  • readonly (bool) – 输入框是否为只读

  • datalist (list) – 输入建议内容列表,在页面上的显示效果为下拉候选列表,用户可以忽略建议内容列表而输入其他内容。仅当输入类型 typeTEXT 时可用

  • help_text (str) – 输入框的帮助文本。帮助文本会以小号字体显示在输入框下方

  • other_html_attrs – 在输入框上附加的额外html属性。参考: https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#%E5%B1%9E%E6%80%A7

返回

用户输入的值

pywebio.input.textarea(label: str = '', *, rows: int = 6, code: Optional[Union[bool, Dict]] = None, maxlength: Optional[int] = None, minlength: Optional[int] = None, validate: Optional[Callable[[Any], Optional[str]]] = None, name: Optional[str] = None, value: Optional[str] = None, onchange: Optional[Callable[[Any], None]] = None, placeholder: Optional[str] = None, required: Optional[bool] = None, readonly: Optional[bool] = None, help_text: Optional[str] = None, **other_html_attrs)[源代码]

文本输入域(多行文本输入)

参数
  • rows (int) – 输入框的最多可显示的文本的行数,内容超出时会显示滚动条

  • maxlength (int) – 最大允许用户输入的字符长度 (Unicode) 。未指定表示无限长度

  • minlength (int) – 最少需要用户输入的字符长度(Unicode)

  • code (dict/bool) –

    通过提供 Codemirror 参数让文本输入域具有代码编辑器样式:

    res = textarea('Text area', code={
        'mode': "python",
        'theme': 'darcula'
    })
    

    可以直接使用 code={}code=True 开启代码编辑样式。代码编辑区支持使用 EscF11 切换全屏。

    这里 列举了一些常用的Codemirror选项

  • label, validate, name, value, onchange, placeholder, required, readonly, help_text, other_html_attrs (-) – 与 input 输入函数的同名参数含义一致

返回

用户输入的文本

pywebio.input.select(label: str = '', options: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, *, multiple: Optional[bool] = None, validate: Optional[Callable[[Any], Optional[str]]] = None, name: Optional[str] = None, value: Optional[Union[List, str]] = None, onchange: Optional[Callable[[Any], None]] = None, native: bool = True, required: Optional[bool] = None, help_text: Optional[str] = None, **other_html_attrs)[源代码]

下拉选择框

默认单选,可以通过设置 multiple 参数来允许多选

参数
  • options (list) –

    可选项列表。列表项的可用形式有:

    • dict:

      {
          "label":(str) 选项标签,
          "value":(object) 选项值,
          "selected":(bool, optional) 是否默认选中,
          "disabled":(bool, optional) 是否禁止选中
      }
      
    • tuple or list: (label, value, [selected,] [disabled])

    • 单值: 此时label和value使用相同的值

    注意:

    1. options 中的 value 可以为任意可JSON序列化对象

    2. multiple 选项不为 True 则可选项列表最多仅能有一项的 selectedTrue

  • multiple (bool) – 是否可以多选. 默认单选

  • value (list or str) – 下拉选择框初始选中项的值。当 multiple=True 时, value 需为list,否则为单个选项的值。 你也可以通过设置 options 列表项中的 selected 字段来设置默认选中选项。 最终选中项为 value 参数和 options 中设置的并集。

  • required (bool) – 是否至少选择一项,仅在 multiple=True 时可用

  • native (bool) – Using browser’s native select component rather than bootstrap-select. This is the default behavior.

  • label, validate, name, onchange, help_text, other_html_attrs (-) – 与 input 输入函数的同名参数含义一致

返回

如果 multiple=True 时,返回用户选中的 options 中的值的列表;否则,返回用户选中的 options 中的值

pywebio.input.checkbox(label: str = '', options: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, *, inline: Optional[bool] = None, validate: Optional[Callable[[Any], Optional[str]]] = None, name: Optional[str] = None, value: Optional[List] = None, onchange: Optional[Callable[[Any], None]] = None, help_text: Optional[str] = None, **other_html_attrs)[源代码]

勾选选项。可以多选,也可以不选。

参数
  • options (list) – 可选项列表。格式与同 select() 函数的 options 参数

  • inline (bool) – 是否将选项显示在一行上。默认每个选项单独占一行

  • value (list) – 勾选选项初始选中项。为选项值的列表。你也可以通过设置 options 列表项中的 selected 字段来设置默认选中选项。

  • label, validate, name, onchange, help_text, other_html_attrs (-) – 与 input 输入函数的同名参数含义一致

返回

用户选中的 options 中的值的列表。当用户没有勾选任何选项时,返回空列表

pywebio.input.radio(label: str = '', options: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, *, inline: Optional[bool] = None, validate: Optional[Callable[[Any], Optional[str]]] = None, name: Optional[str] = None, value: Optional[str] = None, onchange: Optional[Callable[[Any], None]] = None, required: Optional[bool] = None, help_text: Optional[str] = None, **other_html_attrs)[源代码]

单选选项

参数
  • options (list) – 可选项列表。格式与同 select() 函数的 options 参数

  • inline (bool) – 是否将选项显示在一行上。默认每个选项单独占一行

  • value (str) – 可选项列表。格式与同 select() 函数的 options 参数

  • required (bool) – 是否一定要选择一项(默认条件下用户可以不选择任何选项)

  • label, validate, name, onchange, help_text, other_html_attrs (-) – 与 input 输入函数的同名参数含义一致

返回

用户选中的选项的值, 如果用户没有选任何值,返回 None

pywebio.input.actions(label: str = '', buttons: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, name: Optional[str] = None, help_text: Optional[str] = None)[源代码]

按钮选项

在表单上显示为一组按钮,用户点击按钮后依据按钮类型的不同有不同的表现。

参数
  • buttons (list) –

    按钮列表。列表项的可用形式有:

    • dict:

      {
         "label":(str) 按钮标签,
         "value":(object) 按钮值,
         "type":(str, optional) 按钮类型,
         "disabled":(bool, optional) 是否禁止选择,
         "color":(str, optional) 按钮颜色
      
      }
      

      type='reset'/'cancel'disabled=True 可省略 value

    • tuple or list: (label, value, [type], [disabled])

    • 单值: 此时label和value使用相同的值

    其中, value 可以为任意可JSON序列化的对象。

    type 可选值为:

    • 'submit' : 点击按钮后,立即将整个表单提交,最终表单中本项的值为被点击按钮的 value 值。 'submit'type 的默认值

    • 'cancel' : 取消输入。点击按钮后,立即将整个表单提交,表单值返回 None

    • 'reset' : 点击按钮后,将整个表单重置,输入项将变为初始状态。 注意:点击 type=reset 的按钮后,并不会提交表单, actions() 调用也不会返回

    按钮的 color 值可以为: primary, secondary, success, danger, warning, info, light, dark .

  • label, name, help_text (-) – 与 input 输入函数的同名参数含义一致

返回

若用户点击点击 type=submit 按钮进行表单提交,返回用户点击的按钮的值; 若用户点击 type=cancel 按钮或通过其它方式提交表单,则返回 None

actions() 作为 input_group() 中的最后一个输入项、并且含有 type='submit' 的按钮时,input_group() 表单默认的提交按钮会被当前 actions() 替换

actions() 的使用场景

  • 实现简单的选择操作:

confirm = actions('Confirm to delete file?', ['confirm', 'cancel'],
                      help_text='Unrecoverable after file deletion')
if confirm=='confirm':  
    ...  

相比于其他输入项,使用 actions() 用户只需要点击一次就可完成提交。

  • 替换默认的提交按钮:

info = input_group('Add user', [
    input('username', type=TEXT, name='username', required=True),
    input('password', type=PASSWORD, name='password', required=True),
    actions('actions', [
        {'label': 'Save', 'value': 'save'},
        {'label': 'Save and add next', 'value': 'save_and_continue'},
        {'label': 'Reset', 'type': 'reset', 'color': 'warning'},
        {'label': 'Cancel', 'type': 'cancel', 'color': 'danger'},
    ], name='action', help_text='actions'),
])
put_code('info = ' + json.dumps(info, indent=4))
if info is not None:
    save_user(info['username'], info['password'])  
    if info['action'] == 'save_and_continue':
        add_next()  
pywebio.input.file_upload(label: str = '', accept: Optional[Union[List, str]] = None, name: Optional[str] = None, placeholder: str = 'Choose file', multiple: bool = False, max_size: Union[int, str] = 0, max_total_size: Union[int, str] = 0, required: Optional[bool] = None, help_text: Optional[str] = None, **other_html_attrs)[源代码]

文件上传

参数
  • accept (str or list) –

    单值或列表, 表示可接受的文件类型。文件类型的可用形式有:

    • . 字符开始的文件扩展名(例如:.jpg, .png, .doc)。 注意:截至本文档编写之时,微信内置浏览器还不支持这种语法

    • 一个有效的 MIME 类型。 例如: application/pdfaudio/* 表示音频文件、video/* 表示视频文件、image/* 表示图片文件。 参考 https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types

  • placeholder (str) – 未上传文件时,文件上传框内显示的文本

  • multiple (bool) – 是否允许多文件上传,默认关闭

  • max_size (int/str) –

    单个文件的最大大小,超过限制将会禁止上传。

    默认为0,表示不限制上传文件的大小。

    max_size 值可以为数字表示的字节数,或以 K / M / G 结尾表示的字符串(分别表示 千字节、兆字节、吉字节,大小写不敏感)。例如: max_size=500 , max_size='40K' , max_size='3M'

  • max_total_size (int/str) – 所有文件的最大大小,超过限制将会禁止上传。仅在 multiple=True 时可用,默认不限制上传文件的大小。 格式同 max_size 参数

  • required (bool) – 是否必须要上传文件。默认为 False

  • label, name, help_text, other_html_attrs (-) – 与 input 输入函数的同名参数含义一致

返回

multiple=False 时(默认),返回dict:

{
    'filename': 文件名,
    'content':文件二进制数据(bytes object),
    'mime_type': 文件的MIME类型,
    'last_modified': 文件上次修改时间(时间戳)
}

若用户没有上传文件,返回 None

multiple=True 时,返回列表,列表项格式同上文 multiple=False 时的返回值;若用户没有上传文件,返回空列表。

注解

若上传大文件请留意Web框架的文件上传大小限制设置。在使用 start_server()path_deploy() 启动PyWebIO应用时, 可通过 max_payload_size 参数设置Web框架允许上传的最大文件大小

# Upload a file and save to server                      
f = input.file_upload("Upload a file")                  
open('asset/'+f['filename'], 'wb').write(f['content'])  

imgs = file_upload("Select some pictures:", accept="image/*", multiple=True)
for img in imgs:
    put_image(img['content'])
pywebio.input.slider(label: str = '', *, name: Optional[str] = None, value: Union[int, float] = 0, min_value: Union[int, float] = 0, max_value: Union[int, float] = 100, step: int = 1, validate: Optional[Callable[[Any], Optional[str]]] = None, onchange: Optional[Callable[[Any], None]] = None, required: Optional[bool] = None, help_text: Optional[str] = None, **other_html_attrs)[源代码]

滑块输入

参数
  • value (int/float) – 滑块的初始值

  • min_value (int/float) – 滑块最小允许的值

  • max_value (int/float) – 滑块最大允许的值

  • step (int) – 滑动的步长。仅当 valuemin_valuemax_value 全为int时有效

  • label, name, validate, onchange, required, help_text, other_html_attrs (-) – 与 input 输入函数的同名参数含义一致

Return int/float

value, min_valuemax_value 中含有float类型,则返回值为float,否则返回值为int类型

pywebio.input.input_group(label: str = '', inputs: Optional[List] = None, validate: Optional[Callable[[Dict], Optional[Tuple[str, str]]]] = None, cancelable: bool = False)[源代码]

输入组。向页面上展示一组输入

参数
  • label (str) – 输入组标签

  • inputs (list) – 输入项列表。列表的内容为对单项输入函数的调用,并在单项输入函数中传入 name 参数。

  • validate (callable) –

    输入组校验函数。

    函数签名:callback(data) -> (name, error_msg) validate 接收整个表单的值为参数,当校验表单值有效时,返回 None ,当某项输入值无效时,返回出错输入项的 name 值和错误提示. 比如:

def check_form(data):
    if len(data['name']) > 6:
        return ('name', 'Name to long!')
    if data['age'] <= 0:
        return ('age', 'Age cannot be negative!')

data = input_group("Basic info",[
    input('Input your name', name='name'),
    input('Repeat your age', name='age', type=NUMBER)
], validate=check_form)

put_text(data['name'], data['age'])
参数

cancelable (bool) –

表单是否可以取消。若 cancelable=True 则会在表单底部显示一个“取消”按钮,默认为 False

注意:若 inputs 中最后一项输入为 actions() ,则忽略 cancelable

返回

若用户取消表单,返回 None ,否则返回一个 dict , 其键为输入项的 name 值,字典值为输入项的值

pywebio.input.input_update(name: Optional[str] = None, **spec)[源代码]

更新输入项的属性。本函数仅能在输入函数的 onchange 回调中使用。

参数
  • name (str) – 目标输入项的 name 。可选,默认为当前触发 onchange 回调的输入项

  • spec – 需要更新的输入项参数。注意一下参数无法被更新:type, name, validate, action, code, onchange, multiple

一个具有依赖关系的输入项的示例:

country2city = {
    'China': ['Beijing', 'Shanghai', 'Hong Kong'],
    'USA': ['New York', 'Los Angeles', 'San Francisco'],
}
countries = list(country2city.keys())
location = input_group("Select a location", [
    select('Country', options=countries, name='country',
           onchange=lambda c: input_update('city', options=country2city[c])),
    select('City', options=country2city[countries[0]], name='city'),
])

pywebio.output — 输出模块

本模块提供了一系列函数来输出不同形式的内容到用户浏览器,并支持灵活的输出控制。

函数清单

下表为PyWebIO提供的输出相关的函数。
其中标记有 * 的函数表示其支持接收 put_xxx 调用作为参数。
标记有 的函数表示其支持作为上下文管理器使用。

函数

简介

输出域Scope

put_scope

创建一个新的scope.

use_scope

进入输出域

get_scope

获取当前正在使用的输出域

clear

清空scope内容

remove

移除Scope

scroll_to

将页面滚动到 scope Scope处

内容输出

put_text

输出文本

put_markdown

输出Markdown

输出通知消息

put_html

输出Html

put_link

输出链接

put_progressbar

Output a progress bar

put_loading

输出加载提示

put_code

输出代码块

put_table*

输出表格

Output and update data table

输出按钮,并绑定点击事件

put_image

输出图片

put_file

显示一个文件下载链接

put_tabs*

输出横向标签栏Tabs

put_collapse*†

输出可折叠的内容

put_scrollable*†

固定高度内容输出区域
内容超出则显示滚动条
.

put_widget*

输出自定义的控件

其他交互

toast

显示一条通知消息

popup*†

显示弹窗

close_popup

关闭正在显示的弹窗

布局与样式

put_row*†

使用行布局输出内容

put_column*†

使用列布局输出内容

put_grid*

使用网格布局输出内容

span

put_table()put_grid() 中设置内容跨单元格

style*

自定义输出内容的css样式

输出域Scope

pywebio.output.put_scope(name: str, content: Union[pywebio.io_ctrl.Output, List[pywebio.io_ctrl.Output]] = [], scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个输出域

参数
  • name (str) –

  • content (list/put_xxx()) – 输出域里的初始内容,可以为 put_xxx() 调用或其列表。

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

pywebio.output.use_scope(name=None, clear=False)[源代码]

scope的上下文管理器和装饰器。用于创建一个新的输出域并进入,或进入一个已经存在的输出域。

参见 用户手册-use_scope()

参数
  • name (str) – scope名. 若为None则生成一个全局唯一的scope名.(以上下文管理器形式的调用时,上下文管理器会返回scope名)

  • clear (bool) – 在进入scope前是否要清除scope里的内容

Usage

with use_scope(...) as scope_name:
    put_xxx()

@use_scope(...)
def app():
    put_xxx()
pywebio.output.get_scope(stack_idx: int = - 1)[源代码]

获取当前运行时scope栈中的scope名

参数

stack_idx (int) – 当前运行时的scope栈索引。-1表示当前scope,-2表示进入当前scope前的scope,依次类推;0表示 ROOT scope

返回

返回Scope栈中对应索引的scope名,索引错误时返回None

pywebio.output.clear(scope: Optional[str] = None)[源代码]

清空scope内容

参数

scope (str) – 目标scope名。默认为当前scope

pywebio.output.remove(scope: Optional[str] = None)[源代码]

移除Scope

参数

scope (str) – 目标scope名。默认为当前scope

pywebio.output.scroll_to(scope: Optional[str] = None, position: str = 'top')[源代码]

将页面滚动到 scope Scope处

参数
  • scope (str) – Target scope. Default is the current scope.

  • position (str) –

    将Scope置于屏幕可视区域的位置。可用值:

    • 'top' : 滚动页面,让Scope位于屏幕可视区域顶部

    • 'middle' : 滚动页面,让Scope位于屏幕可视区域中间

    • 'bottom' : 滚动页面,让Scope位于屏幕可视区域底部

内容输出

Scope related parameters of output function

输出函数默认将内容输出到“当前scope”,“当前scope”可由 use_scope() 设置。

另外,所有输入函数都支持使用 scope 参数来指定输出的目的scope:

with use_scope('scope3'):
    put_text('text1 in scope3')   # output to current scope: scope3
    put_text('text in ROOT scope', scope='ROOT')   # output to ROOT Scope

put_text('text2 in scope3', scope='scope3')   # output to scope3

以上代码运行结果如下:

text1 in scope3
text2 in scope3
text in ROOT scope

一个scope可以包含多个输出项,输出函数的默认行为是将内容追加到目标scope中。可以使用输出函数的 position 参数来指定输出内容在目标scope中的插入位置。

一个Scope中各次输出的元素具有像数组一样的索引,最前面的编号为0,以此往后递增加一;同样可以使用负数对Scope中的元素进行索引,-1表示最后面的元素,-2表示次后面的元素……

position 参数类型为整形, position>=0 时表示输出内容到目标Scope的第position号元素的前面; position<0 时表示输出内容到目标Scope第position号元素之后:

with use_scope('scope1'):
    put_text('A')
    put_text('B', position=0)   # insert B before A -> B A
    put_text('C', position=-2)  # insert C after B -> B C A
    put_text('D', position=1)   # insert D before C B -> B D C A

Output functions

pywebio.output.put_text(*texts: Any, sep: str = ' ', inline: bool = False, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出文本

参数
  • texts – 要输出的内容。类型可以为任意对象,对非字符串对象会应用 str() 函数作为输出值。

  • sep (str) – 输出分隔符

  • inline (bool) – 将文本作为行内元素(连续输出的文本显示在相同的段落中)。默认每次输出的文本都作为一个独立的段落

  • scope (str) –

    内容输出的目标scope,若scope不存在,则不进行任何输出操作。

    可以直接指定目标Scope名,或者使用int通过索引Scope栈来确定Scope

  • position (int) – 在scope中输出的位置。

参数 scopeposition 的更多使用说明参见 用户手册

pywebio.output.put_markdown(mdcontent: str, lstrip: bool = True, options: Optional[Dict[str, Union[str, bool]]] = None, sanitize: bool = True, scope: Optional[str] = None, position: int = - 1, **kwargs)pywebio.io_ctrl.Output[源代码]

输出Markdown

参数
  • mdcontent (str) – Markdown文本

  • lstrip (bool) – 是否自动移除 mdcontent 每一行的前导空白锁进

  • options (dict) – 解析Markdown时的配置参数。 PyWebIO使用 marked 解析Markdown, 可配置项参见: https://marked.js.org/using_advanced#options (仅支持配置string和boolean类型的项)

  • sanitize (bool) – 是否使用 DOMPurify 对内容进行过滤来防止XSS攻击。

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

当使用python三引号语法在函数中输出多行Markdown内容时,你可以缩进Markdown内容来使代码保持美观。PyWebIO会智能地移除Markdown中的缩进:

# good code format
def hello():
    put_markdown(r""" # H1
    This is content.
    """)

在 1.5 版更改: Enable lstrip by default. Deprecate strip_indent.

pywebio.output.put_info(*contents, closable=False, scope=None, position=- 1)Output:[源代码]
pywebio.output.put_success(*contents, closable=False, scope=None, position=- 1)Output:[源代码]
pywebio.output.put_warning(*contents, closable=False, scope=None, position=- 1)Output:[源代码]
pywebio.output.put_error(*contents, closable=False, scope=None, position=- 1)Output:[源代码]

输出通知消息

参数
  • contents – 消息内容. 元素为 put_xxx() 调用,其他类型会被转换成 put_text(content)

  • closable (bool) – 是否在消息框右侧展示一个关闭按钮。

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

1.2 新版功能.

pywebio.output.put_html(html: Any, sanitize: bool = False, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出Html内容

参数
  • html – html字符串

  • sanitize (bool) – 是否使用 DOMPurify 对内容进行过滤来防止XSS攻击。

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

输出链接到其他网页或PyWebIO App的超链接

参数
  • name (str) – 链接名称

  • url (str) – 链接到的页面地址

  • app (str) – 链接到的PyWebIO应用名。参见 Server模式

  • new_window (bool) – 是否在新窗口打开链接

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

urlapp 参数必须指定一个但不可以同时指定

pywebio.output.put_progressbar(name: str, init: float = 0, label: Optional[str] = None, auto_close: bool = False, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

Output a progress bar

参数
  • name (str) – 进度条名称,为进度条的唯一标识

  • init (float) – 进度条初始值. 进度条的值在 0 ~ 1 之间

  • label (str) – The label of progress bar. The default is the percentage value of the current progress.

  • auto_close (bool) – 是否在进度完成后关闭进度条

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example:

import time

put_progressbar('bar');
for i in range(1, 11):
    set_progressbar('bar', i / 10)
    time.sleep(0.1)

参见

use set_progressbar() to set the progress of progress bar

pywebio.output.set_progressbar(name: str, value: float, label: Optional[str] = None)[源代码]

设置进度条进度

参数
  • name (str) – 设置进度条进度

  • value (float) – 进度条的值. 范围在 0 ~ 1 之间

  • label (str) – The label of progress bar. The default is the percentage value of the current progress.

See also: put_progressbar()

pywebio.output.put_loading(shape: str = 'border', color: str = 'dark', scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出加载提示

参数
  • shape (str) – 加载提示的形状, 可选值: 'border' (默认,旋转的圆环)、 'grow' (大小渐变的圆点)

  • color (str) – 加载提示的颜色, 可选值: 'primary''secondary''success''danger''warning''info''light''dark' (默认)

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

put_loading() 支持直接调用和上下文管理器:

for shape in ('border', 'grow'):
    for color in ('primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark'):
        put_text(shape, color)
        put_loading(shape=shape, color=color)

# The loading prompt and the output inside the context will disappear
# automatically when the context block exits.
with put_loading():
    put_text("Start waiting...")
    time.sleep(3)  # Some time-consuming operations
put_text("The answer of the universe is 42")

# using style() to set the size of the loading prompt
put_loading().style('width:4rem; height:4rem')

在 1.8 版更改: when use put_loading() as context manager, the output inside the context will also been removed after the context block exits.

pywebio.output.put_code(content: str, language: str = '', rows: Optional[int] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出代码块

参数
  • content (str) – 代码内容

  • language (str) – 代码语言

  • rows (int) – 代码块最多可显示的文本行数,默认不限制。内容超出时会使用滚动条。

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

pywebio.output.put_table(tdata: List[Union[List, Dict]], header: List[Union[str, Tuple[Any, str]]] = None, scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出表格

参数
  • tdata (list) – 表格数据。列表项可以为 list 或者 dict , 单元格的内容可以为字符串或 put_xxx 类型的输出函数。 数组项可以使用 span() 函数来设定单元格跨度。

  • header (list) –

    表头。当 tdata 的列表项为 list 类型时,若省略 header 参数,则使用 tdata 的第一项作为表头。表头项可以使用 span() 函数来设定单元格跨度。

    When tdata is list of dict, header can be used to specify the order of table headers. In this case, the header can be a list of dict key or a list of (<label>, <dict key>).

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example:

# 'Name' cell across 2 rows, 'Address' cell across 2 columns
put_table([
    [span('Name',row=2), span('Address', col=2)],
    ['City', 'Country'],
    ['Wang', 'Beijing', 'China'],
    ['Liu', 'New York', 'America'],
])

# Use `put_xxx()` in `put_table()`
put_table([
    ['Type', 'Content'],
    ['html', put_html('X<sup>2</sup>')],
    ['text', '<hr/>'],
    ['buttons', put_buttons(['A', 'B'], onclick=...)],  
    ['markdown', put_markdown('`Awesome PyWebIO!`')],
    ['file', put_file('hello.text', b'hello world')],
    ['table', put_table([['A', 'B'], ['C', 'D']])]
])

# Set table header
put_table([
    ['Wang', 'M', 'China'],
    ['Liu', 'W', 'America'],
], header=['Name', 'Gender', 'Address'])

# When ``tdata`` is list of dict
put_table([
    {"Course":"OS", "Score": "80"},
    {"Course":"DB", "Score": "93"},
], header=["Course", "Score"])  # or header=[(put_markdown("*Course*"), "Course"), (put_markdown("*Score*") ,"Score")]

0.3 新版功能: 单元格的内容支持 put_xxx 类型的输出函数

pywebio.output.span(content: Union[str, pywebio.io_ctrl.Output], row: int = 1, col: int = 1)[源代码]

用于在 put_table()put_grid() 中设置内容跨单元格

参数
  • content – 单元格内容。可以为字符串或 put_xxx() 调用。

  • row (int) – 竖直方向跨度, 即:跨行的数目

  • col (int) – 水平方向跨度, 即:跨列的数目

Example

put_table([
    ['C'],
    [span('E', col=2)],  # 'E' across 2 columns
], header=[span('A', row=2), 'B'])  # 'A' across 2 rows

put_grid([
    [put_text('A'), put_text('B')],
    [span(put_text('A'), col=2)],  # 'A' across 2 columns
])
pywebio.output.put_buttons(buttons: List[Union[Dict[str, Any], Tuple[str, Any], List, str]], onclick: Union[Callable[[Any], None], Sequence[Callable[], None]]], small: Optional[bool] = None, link_style: bool = False, outline: bool = False, group: bool = False, scope: Optional[str] = None, position: int = - 1, **callback_options)pywebio.io_ctrl.Output[源代码]

输出一组按钮,并绑定点击事件

参数
  • buttons (list) –

    按钮列表。列表项的可用形式有:

    • dict:

      {
          "label":(str) 按钮标签,,
          "value":(str) 按钮值,
          "color":(str, optional) 按钮颜色,
          "disabled":(bool, optional) 按钮时否被禁用
      }
      
    • tuple or list: (label, value)

    • 单值: 此时label和value使用相同的值

    其中, value 可以为任意对象。使用dict类型的列表项时,支持使用 color key设置按钮颜色,可选值为 primarysecondarysuccessdangerwarninginfolightdark .

    Example:

    put_buttons([dict(label='success', value='s', color='success')], onclick=...)  
    

  • onclick (callable / list) –

    按钮点击回调函数. onclick 可以是函数或者函数组成的列表.

    onclick 为函数时, 签名为 onclick(btn_value). btn_value 为被点击的按钮的 value

    onclick 为列表时,列表内函数的签名为 func(). 此时,回调函数与 buttons 一一对应

    Tip: 可以使用 functools.partial 来在 onclick 中保存更多上下文信息.

    Note: 当使用 基于协程的会话实现 时,回调函数可以为协程函数.

  • small (bool) – 是否使用小号按钮,默认为False

  • link_style (bool) – 是否将按钮显示为链接样式,默认为False

  • outline (bool) – 是否将按钮显示为镂空样式,默认为False

  • group (bool) – 是否将按钮合并在一起,默认为False

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

  • callback_options

    回调函数的其他参数。根据选用的 session 实现有不同参数

    CoroutineBasedSession 实现
    • mutex_mode: 互斥模式。默认为 False 。若为 True ,则在运行回调函数过程中,无法响应当前按钮组的新点击事件,仅当 onclick 为协程函数时有效

    ThreadBasedSession 实现
    • serial_mode: 串行模式模式。默认为 False ,此时每次触发回调,回调函数会在新线程中立即执行。

    开启serial_mode后,该按钮的回调会在会话内的一个固定线程内串行执行,且其他所有新的点击事件的回调(包括 serial_mode=False 的回调)都将排队等待当前点击事件运行完成。如果回调函数运行时间很短,可以开启 serial_mode 来提高性能。

Example:

from functools import partial

def row_action(choice, id):
    put_text("You click %s button with id: %s" % (choice, id))

put_buttons(['edit', 'delete'], onclick=partial(row_action, id=1))

def edit():
    put_text("You click edit button")
def delete():
    put_text("You click delete button")

put_buttons(['edit', 'delete'], onclick=[edit, delete])

在 1.5 版更改: Add disabled button support. The value of button can be any object.

pywebio.output.put_button(label: str, onclick: Callable[], None], color: Optional[str] = None, small: Optional[bool] = None, link_style: bool = False, outline: bool = False, disabled: bool = False, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个按钮,并绑定点击事件

参数
  • label (str) – Button label

  • onclick (callable) – 按钮点击回调函数

  • color (str) – 按钮颜色。可选值为 primarysecondarysuccessdangerwarninginfolightdark .

  • disabled (bool) – Whether the button is disabled

  • small, link_style, outline, scope, position (-) – 与 put_buttons() 函数的同名参数含义一致

Example:

put_button("click me", onclick=lambda: toast("Clicked"), color='success', outline=True)

1.4 新版功能.

在 1.5 版更改: add disabled parameter

pywebio.output.put_image(src: Union[str, bytes, PIL.Image.Image], format: Optional[str] = None, title: str = '', width: Optional[str] = None, height: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出图片

参数
  • src – 图片内容. 可以为: 字符串类型的URL, bytes-like object 表示的图片二进制内容, PIL.Image.Image 实例

  • title (str) – 图片描述

  • width (str) – 图像的宽度,可以是CSS像素(数字px)或者百分比(数字%)。

  • height (str) – 图像的高度,可以是CSS像素(数字px)或者百分比(数字%)。可以只指定 width 和 height 中的一个值,浏览器会根据原始图像进行缩放。

  • format (str) – 图片格式,非必须。如 png , jpeg , gif 等, 仅在 src 为非URL时有效

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example:

img = open('/path/to/some/image.png', 'rb').read()  
put_image(img, width='50px')

put_image('https://www.python.org/static/img/python-logo.png')
pywebio.output.put_file(name: str, content: bytes, label: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

显示一个文件下载链接

在浏览器上的显示为一个以文件名为名的链接,点击链接后浏览器自动下载文件。

参数
  • name (str) – 下载保存为的文件名

  • content – 文件内容. 类型为 bytes-like object

  • label (str) – 下载链接的显示文本,默认和文件名相同

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example:

content = open('./some-file', 'rb').read()  
put_file('hello-world.txt', content, 'download me')
pywebio.output.put_tabs(tabs: List[Dict[str, Any]], scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出横向标签栏Tabs

参数
  • tabs (list) – 标签列表,列表项为一个 dict: {"title": "Title", "content": ...} ,其中 content 表示标签内容,可以为字符串、 put_xxx() 调用或由它们组成的列表。

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

put_tabs([
    {'title': 'Text', 'content': 'Hello world'},
    {'title': 'Markdown', 'content': put_markdown('~~Strikethrough~~')},
    {'title': 'More content', 'content': [
        put_table([
            ['Commodity', 'Price'],
            ['Apple', '5.5'],
            ['Banana', '7'],
        ]),
        put_link('pywebio', 'https://github.com/wang0618/PyWebIO')
    ]},
])

1.3 新版功能.

pywebio.output.put_collapse(title: str, content: Union[str, pywebio.io_ctrl.Output, List[Union[str, pywebio.io_ctrl.Output]]] = [], open: bool = False, scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出可折叠的内容

参数
  • title (str) – 内容标题

  • content (list/str/put_xxx()) – 内容可以为字符串或 put_xxx 类输出函数的返回值,或者由它们组成的列表。

  • open (bool) – 是否默认展开折叠内容。默认不展开内容

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example:

put_collapse('Collapse title', [
    'text',
    put_markdown('~~Strikethrough~~'),
    put_table([
        ['Commodity', 'Price'],
        ['Apple', '5.5'],
    ])
], open=True)

put_collapse('Large text', 'Awesome PyWebIO! '*30)
pywebio.output.put_scrollable(content: Union[str, pywebio.io_ctrl.Output, List[Union[str, pywebio.io_ctrl.Output]]] = [], height: Union[int, Tuple[int, int]] = 400, keep_bottom: bool = False, border: bool = True, scope: str = None, position: int = - 1, **kwargs)pywebio.io_ctrl.Output[源代码]

固定高度内容输出区域,内容超出则显示滚动条

参数
  • content (list/str/put_xxx()) – 内容可以为字符串或 put_xxx 类输出函数的返回值,或者由它们组成的列表。

  • height (int/tuple) – 区域的高度(像素),内容超出此高度则使用滚动条。可以传入 (min_height, max_height) 来表示高度的范围,比如 (100, 200) 表示区域高度最小100像素、最高200像素。若不想限制高度,则传入 None

  • keep_bottom (bool) – Whether to keep the content area scrolled to the bottom when updated.

  • border (bool) – 是否显示边框

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example:

import time

put_scrollable(put_scope('scrollable'), height=200, keep_bottom=True)
put_text("You can click the area to prevent auto scroll.", scope='scrollable')

while 1:
    put_text(time.time(), scope='scrollable')
    time.sleep(0.5)

在 1.1 版更改: 添加 height 参数,移除 max_height 参数;添加 keep_bottom 参数

在 1.5 版更改: remove horizon_scroll parameter

pywebio.output.put_datatable(records: Sequence[Mapping], actions: Sequence[Tuple[str, Callable[[Union[str, int, List[Union[str, int]]]], None]]] = None, onselect: Callable[[Union[str, int, List[Union[str, int]]]], None] = None, multiple_select=False, id_field: str = None, height: Union[str, int] = 600, theme: Literal[‘alpine’, ‘alpine-dark’, ‘balham’, ‘balham-dark’, ‘material’] = 'balham', cell_content_bar=True, instance_id='', column_order: Union[Sequence[str], Mapping] = None, column_args: Mapping[Union[str, Tuple], Mapping] = None, grid_args: Mapping[str, Any] = None, enterprise_key='', scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

Output a datatable.

Compared with put_table(), put_datatable() is more suitable for displaying large amounts of data (both data fields and data entries), while put_table() is more suitable for displaying diverse data types (pictures, buttons, etc.) in cells.

This widget is powered by the awesome ag-grid library.

参数
  • records (list[dict]) – data of rows, each row is a python dict, which can be nested.

  • actions (list) – actions for selected row(s), they will be shown as buttons when row is selected. The format of the action item: (button_label:str, on_click:callable). Specifically, None item is allowed, which will be rendered as a separator. The on_click callback receives the selected row ID as parameter.

  • onselect (callable) – callback when row is selected, receives the selected row ID as parameter.

  • multiple_select (bool) – whether multiple rows can be selected. When enabled, the on_click callback in actions and the onselect callback will receive ID list of selected rows as parameter.

  • id_field (str/tuple) –

    row ID field, that is, the key of the row dict to uniquely identifies a row. When not provide, the datatable will use the index in records to assign row ID.

    None

    To specify the ID field of a nested dict, use a tuple to specify the path of the ID field. For example, if the row record is in {'a': {'b': ...}} format, you can use id_field=('a', 'b') to set 'b' column as the ID field.

  • height (int/str) – widget height. When pass int type, the unit is pixel, when pass str type, you can specify any valid CSS height value. In particular, you can use 'auto' to make the datatable auto-size it’s height to fit the content.

  • theme (str) – datatable theme. Available themes are: 'balham' (default), 'alpine', 'alpine-dark', 'balham-dark', 'material'. You can preview the themes in ag-grid official example.

  • cell_content_bar (bool) – whether to add a text bar to datatable to show the content of current focused cell. Default is True.

  • instance_id (str) – Assign a unique ID to the datatable, so that you can refer this datatable in datatable_update(), datatable_insert() and datatable_remove() functions.

  • column_order (list) –

    column order, the order of the column names in the list will be used as the column order. If not provided, the column order will be the same as the order of the keys in the first row of records. When provided, the column not in the list will not be shown. Note that column_order must be specified when records is empty.

    None

    Since the dict in python is ordered after py3.7, you can use dict to specify the column order when the row record is nested dict. For example:

    column_order = {'a': {'b': {'c': None, 'd': None}, 'e': None}, 'f': None}
    

  • column_args

    column properties. Dict type, the key is str to specify the column field, the value is ag-grid column properties in dict.

    None

    Given the row record is in this format:

    {
        "a": {"b": ..., "c": ...},
        "b": ...,
        "c": ...
    }
    

    When you set column_args={"b": settings}, the column settings will be applied to the column a.b and b. Use tuple as key to specify the nested key path, for example, column_args={("a", "b"): settings} will only apply the settings to column a.b.

  • grid_args – ag-grid grid options. Refer ag-grid doc - grid options for more information.

  • enterprise_key (str) – ag-grid enterprise license key. When not provided, will use the ag-grid community version.

The ag-grid library is so powerful, and you can use the column_args and grid_args parameters to achieve high customization.

Example of put_datatable():

import urllib.request
import json

with urllib.request.urlopen('https://fakerapi.it/api/v1/persons?_quantity=30') as f:
    data = json.load(f)['data']

put_datatable(
    data,
    actions=[
        ("Edit Email", lambda row_id: datatable_update('user', input("Email"), row_id, "email")),
        ("Insert a Row", lambda row_id: datatable_insert('user', data[0], row_id)),
        None,  # separator
        ("Delete", lambda row_id: datatable_remove('user', row_id)),
    ],
    onselect=lambda row_id: toast(f'Selected row: {row_id}'),
    instance_id='user'
)
None

The ag-grid instance can be accessed with JS global variable ag_grid_${instance_id}_promise:

ag_grid_xxx_promise.then(function(gridOptions) {
    // gridOptions is the ag-grid gridOptions object
    gridOptions.columnApi.autoSizeAllColumns();
});

To pass JS functions as value of column_args or grid_args, you can use JSFunction object:

pywebio.output.JSFunction([param1, ][param2, ]..., [param n, ]body)[源代码]

Example:

put_datatable(..., grid_args=dict(sortChanged=JSFunction("event", "console.log(event.source)")))

Since the ag-grid don’t native support nested dict as row record, PyWebIO will internally flatten the nested dict before passing to ag-grid. So when you access or modify data in ag-grid directly, you need to use the following functions to help you convert the data:

  • gridOptions.flatten_row(nested_dict_record): flatten the nested dict record to a flat dict record

  • gridOptions.path2field(field_path_array): convert the field path array to field name used in ag-grid

  • gridOptions.field2path(ag_grid_column_field_name): convert the field name back to field path array

The implement of datatable_update(), datatable_insert and datatable_remove functions are good examples to show how to interact with ag-grid in Javascript.

pywebio.output.datatable_update(instance_id: str, data: Any, row_id: Optional[Union[str, int]] = None, field: Optional[Union[str, List[str], Tuple[str]]] = None)[源代码]

Update the whole data / a row / a cell of the datatable.

To use datatable_update(), you need to specify the instance_id parameter when calling put_datatable().

When row_id and field is not specified (datatable_update(instance_id, data)), the whole data of datatable will be updated, in this case, the data parameter should be a list of dict (same as records in put_datatable()).

To update a row, specify the row_id parameter and pass the row data in dict to data parameter (datatable_update(instance_id, data, row_id)). See id_field of put_datatable() for more info of row_id.

To update a cell, specify the row_id and field parameters, in this case, the data parameter should be the cell value To update a row, specify the row_id parameter and pass the row data in dict to data parameter (datatable_update(instance_id, data, row_id, field)). The field can be a tuple to indicate nested key path.

pywebio.output.datatable_insert(instance_id: str, records: List, row_id=None)[源代码]

Insert rows to datatable.

参数
  • instance_id (str) – Datatable instance id (i.e., the instance_id parameter when calling put_datatable())

  • records (dict/list[dict]) – row record or row record list to insert

  • row_id (str/int) – row id to insert before, if not specified, insert to the end

Note:

When use id_field=None (default) in put_datatable(), the row id of new inserted rows will auto increase from the last max row id.

pywebio.output.datatable_remove(instance_id: str, row_ids: List)[源代码]

Remove rows from datatable.

参数
  • instance_id (str) – Datatable instance id (i.e., the instance_id parameter when calling put_datatable())

  • row_ids (int/str/list) – row id or row id list to remove

pywebio.output.put_widget(template: str, data: Dict[str, Any], scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出自定义的控件

参数
  • template – html模版,使用 mustache.js 语法

  • data (dict) –

    渲染模版使用的数据.

    数据可以包含输出函数( put_xxx() )的返回值, 可以使用 pywebio_output_parse 函数来解析 put_xxx() 内容;对于字符串输入, pywebio_output_parse 会将解析成文本.

    ⚠️:使用 pywebio_output_parse 函数时,需要关闭mustache的html转义: {{& pywebio_output_parse}} , 参见下文示例.

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example

tpl = '''
<details {{#open}}open{{/open}}>
    <summary>{{title}}</summary>
    {{#contents}}
        {{& pywebio_output_parse}}
    {{/contents}}
</details>
'''

put_widget(tpl, {
    "open": True,
    "title": 'More content',
    "contents": [
        'text',
        put_markdown('~~Strikethrough~~'),
        put_table([
            ['Commodity', 'Price'],
            ['Apple', '5.5'],
            ['Banana', '7'],
        ])
    ]
})

其他交互

pywebio.output.toast(content: str, duration: float = 2, position: str = 'center', color: str = 'info', onclick: Optional[Callable[], None]] = None)[源代码]

显示一条通知消息

参数
  • content (str) – 通知内容

  • duration (float) – 通知显示持续的时间,单位为秒。 0 表示不自动关闭(此时消息旁会显示一个关闭图标,用户可以手动关闭消息)

  • position (str) – 通知消息显示的位置,可以为 'left' / 'center' / 'right'

  • color (str) – 通知消息的背景颜色,可以为 'info' / 'error' / 'warn' / 'success' 或以 '#' 开始的十六进制颜色值

  • onclick (callable) –

    点击通知消息时的回调函数,回调函数不接受任何参数。

    Note: 当使用 基于协程的会话实现 时,回调函数可以为协程函数.

Example:

def show_msg():
    put_text("You clicked the notification.")

toast('New messages', position='right', color='#2188ff', duration=0, onclick=show_msg)
pywebio.output.popup(title: str, content: Union[str, pywebio.io_ctrl.Output, List[Union[str, pywebio.io_ctrl.Output]]] = None, size: str = 'normal', implicit_close: bool = True, closable: bool = True)[源代码]

显示弹窗

⚠️: PyWebIO不允许同时显示多个弹窗,在显示新弹窗前,会自动关闭页面上存在的弹窗。可以使用 close_popup() 主动关闭弹窗

参数
  • title (str) – 弹窗标题

  • content (list/str/put_xxx()) – The content of the popup. Can be a string, the put_xxx() calls, or a list of them.

  • size (str) – 弹窗窗口大小,可选值: 'large', 'normal' and 'small'.

  • implicit_close (bool) – 是否可以通过点击弹窗外的内容或按下 Esc 键来关闭弹窗,默认为 False

  • closable (bool) – 是否可由用户关闭弹窗. 默认情况下,用户可以通过点击弹窗右上角的关闭按钮来关闭弹窗。 设置为 False 时弹窗仅能通过 popup_close() 关闭,此时 implicit_close 参数将被忽略.

popup() can be used in 2 ways: direct call and context manager.

  • 直接传入内容:

popup('popup title', 'popup text content', size=PopupSize.SMALL)

popup('Popup title', [
    put_html('<h3>Popup Content</h3>'),
    'html: <br/>',
    put_table([['A', 'B'], ['C', 'D']]),
    put_buttons(['close_popup()'], onclick=lambda _: close_popup())
])
  • 作为上下文管理器使用:

with popup('Popup title') as s:
    put_html('<h3>Popup Content</h3>')
    put_text('html: <br/>')
    put_buttons([('clear()', s)], onclick=clear)

put_text('Also work!', scope=s)

上下文管理器会开启一个新的输出scope并返回scope名。在上下文管理器中的输出内容默认会输出到popup窗口中。在上下文管理器退出后,popup窗口并不会随之关闭,你可以继续使用输出函数的 scope 参数来输出内容到popup窗口内。

pywebio.output.close_popup()[源代码]

关闭正在显示的弹窗

See also: popup()

布局与样式

pywebio.output.put_row(content: List[Optional[pywebio.io_ctrl.Output]] = [], size: str = None, scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

使用行布局输出内容. 内容在水平方向从左往右排列成一行

参数
  • content (list) – 子元素列表, 列表项为 put_xxx() 调用或者 None , None 表示空白行间距

  • size (str) –

    用于指示子元素的宽度, 为空格分割的宽度值列表.
    宽度值需要和 content 中子元素一一对应( None 子元素也要对应宽度值).
    size 默认给 None 元素分配10像素宽度,并为剩余元素平均分配宽度.

    宽度值可用格式:

    • 像素值: 例如: 100px

    • 百分比: 表示占可用宽度的百分比. 例如: 33.33%

    • fr 关键字: 表示比例关系, 2fr 表示的宽度为 1fr 的两倍

    • auto 关键字: 表示由浏览器自己决定长度

    • minmax(min, max) : 产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。 例如: minmax(100px, 1fr) 表示长度不小于100px,不大于1fr

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

Example

# Two code blocks of equal width, separated by 10 pixels
put_row([put_code('A'), None, put_code('B')])

# The width ratio of the left and right code blocks is 2:3, which is equivalent to size='2fr 10px 3fr'
put_row([put_code('A'), None, put_code('B')], size='40% 10px 60%')
pywebio.output.put_column(content: List[Optional[pywebio.io_ctrl.Output]] = [], size: str = None, scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

使用列布局输出内容. 内容在竖直方向从上往下排列成一列

参数
  • content (list) – 子元素列表, 列表项为 put_xxx() 调用或者 None , None 表示空白行间距

  • size (str) – 用于指示子元素的高度, 为空格分割的高度值列表. 可用格式参考 put_row() 函数的 size 参数注释.

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

pywebio.output.put_grid(content: List[List[Optional[pywebio.io_ctrl.Output]]], cell_width: str = 'auto', cell_height: str = 'auto', cell_widths: str = None, cell_heights: str = None, direction: str = 'row', scope: str = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

使用网格布局输出内容

参数
  • content – 输出内容. put_xxx() / None 组成的二维数组, None 表示空白. 数组项可以使用 span() 函数设置元素在网格的跨度.

  • cell_width (str) – 网格元素的宽度.

  • cell_height (str) – 网格元素的高度.

  • cell_widths (str) – 网格每一列的宽度. 宽度值用空格分隔. 不可以和 cell_width 参数同时使用.

  • cell_heights (str) – 网格每一行的高度. 高度值用空格分隔. 不可以和 cell_height 参数同时使用.

  • direction (str) –

    排列方向. 为 'row''column' .

    'row' 时表示,content中的每一个子数组代表网格的一行;
    'column' 时表示,content中的每一个子数组代表网格的一列.

  • scope, position (int) – 与 put_text 函数的同名参数含义一致

cell_width,``cell_height``,``cell_widths``,``cell_heights`` 参数中的宽度/高度值格式参考 put_row() 函数的 size 参数注释.

Example:

put_grid([
    [put_text('A'), put_text('B'), put_text('C')],
    [None, span(put_text('D'), col=2, row=1)],
    [put_text('E'), put_text('F'), put_text('G')],
], cell_width='100px', cell_height='100px')
pywebio.output.style(outputs: Union[pywebio.io_ctrl.Output, List[pywebio.io_ctrl.Output]], css_style: str)Union[pywebio.io_ctrl.Output, pywebio.io_ctrl.OutputList][源代码]

自定义输出内容的css样式

1.3 版后已移除: 为输出设置样式的新方式参见 User Guide.

参数
  • outputs (list/put_xxx()) – 输出内容,可以为 put_xxx() 调用或其列表。outputs为列表时将为每个列表项都添加自定义的css样式。

  • css_style (str) – css样式字符串

返回

添加了css样式的输出内容

Note: 若 outputs 为list,则 outputs 中每一项都会被添加css样式, 其返回值可用于任何接受 put_xxx() 列表的地方。

Example

style(put_text('Red'), 'color:red')

style([
    put_text('Red'),
    put_markdown('~~del~~')
], 'color:red')

put_table([
    ['A', 'B'],
    ['C', style(put_text('Red'), 'color:red')],
])

put_collapse('title', style([
    put_text('text'),
    put_markdown('~~del~~'),
], 'margin-left:20px'))

pywebio.session — 会话相关

pywebio.session.download(name, content)[源代码]

向用户推送文件,用户浏览器会将文件下载到本地

参数
  • name (str) – 下载保存为的文件名

  • content – 文件内容. 类型为 bytes-like object

Example:

put_button('Click to download', lambda: download('hello-world.txt', b'hello world!'))
pywebio.session.run_js(code_, **args)[源代码]

在用户浏览器中运行JavaScript代码.

代码运行在浏览器的JS全局作用域中

参数
  • code (str) – js代码

  • args – 传递给js代码的局部变量。变量值需要可以被json序列化

Example:

run_js('console.log(a + b)', a=1, b=2)
pywebio.session.eval_js(expression_, **args)[源代码]

在用户浏览器中执行JavaScript表达式,并获取表达式的值

参数
  • expression (str) – JavaScript表达式。表达式的值需要可以被JSON序列化。如果表达式的值是一个 promiseeval_js() 会一直等待promise被resolve,然后返回它的值,若promise被reject,则返回 None

  • args – 传递给js代码的局部变量。变量值需要可以被json序列化

返回

js表达式的值

注意⚠️:在 基于协程 的会话上下文中,需要使用 await eval_js(expression) 语法来进行调用。

Example:

current_url = eval_js("window.location.href")

function_res = eval_js('''(function(){
    var a = 1;
    a += b;
    return a;
})()''', b=100)

promise_res = eval_js('''new Promise(resolve => {
    setTimeout(() => {
        resolve('Returned inside callback.');
    }, 2000);
});''')

在 1.3 版更改: The JS expression support return promise.

pywebio.session.register_thread(thread: threading.Thread)[源代码]

注册线程,以便在线程内调用 PyWebIO 交互函数。

仅能在默认的基于线程的会话上下文中调用。

参见 Server模式下并发与会话的结束

参数

thread (threading.Thread) – 线程对象

pywebio.session.defer_call(func)[源代码]

设置会话结束时调用的函数。

无论是用户主动关闭会话还是任务结束会话关闭,设置的函数都会被运行。

在会话中可以多次调用 defer_call() ,会话结束后将会顺序执行设置的函数。

defer_call 同样支持以装饰器的方式使用:

@defer_call
def cleanup():
   pass

注意

通过 defer_call() 设置的函数被调用时会话已经关闭,所以在函数体内不可以调用 PyWebIO 的交互函数

pywebio.session.local

当前会话的数据对象(session-local object)。

local 是一个可以通过属性取值的字典,它的目标是用来存储应用中会话独立的状态。 local 中存储的内容不会在会话之间共享,每个会话只能访问到自己存储在其中的数据。

使用场景

当需要在多个函数中保存一些会话独立的数据时,使用session-local对象保存状态会比通过函数参数传递更方便。

以下是一个会话独立的计数器的实现示例:

from pywebio.session import local
def add():
    local.cnt = (local.cnt or 0) + 1

def show():
    put_text(local.cnt or 0)

def main():
    put_buttons(['Add counter', 'Show counter'], [add, show])

而通过函数参数传递状态的实现方式为:

from functools import partial
def add(cnt):
    cnt[0] += 1

def show(cnt):
    put_text(cnt[0])

def main():
    cnt = [0]  # Trick: to pass by reference
    put_buttons(['Add counter', 'Show counter'], [partial(add, cnt), partial(show, cnt)])

当然,还可以通过函数闭包来实现相同的功能:

def main():
    cnt = 0

    def add():
        nonlocal cnt
        cnt += 1

    def show():
        put_text(cnt)

    put_buttons(['Add counter', 'Show counter'], [add, show])
local对象支持的操作

local 是一个可以通过属性访问的字典,访问不存在的属性时会返回 None 而不是抛出异常。local 不支持字典的方法,支持使用 in 操作符来判断键是否存在,可以使用 local._dict 获取底层的字典表示。

local.name = "Wang"
local.age = 22
assert local.foo is None
local[10] = "10"

for key in local:
    print(key)

assert 'bar' not in local
assert 'name' in local

print(local._dict)

1.1 新版功能.

pywebio.session.set_env(**env_info)[源代码]

当前会话的环境设置

可配置项有:

  • title (str): 当前页面的标题

  • output_animation (bool): 是否启用输出动画(在输出内容时,使用过渡动画),默认启用

  • auto_scroll_bottom (bool): 是否在内容输出时将页面自动滚动到底部,默认关闭。注意,开启后,只有输出到ROOT Scope才可以触发自动滚动。

  • http_pull_interval (int): HTTP轮询后端消息的周期(单位为毫秒,默认1000ms),仅在基于HTTP连接的会话(使用Flask或Django后端)中可用

  • input_panel_fixed (bool): 是否将输入栏固定在页面底部, 默认启用。

  • input_panel_min_height (int): 输入栏的最小高度(像素, 默认为300px,最小允许 75px)。仅当 input_panel_fixed=True 时可用。

  • input_panel_init_height (int): 输入栏的初始高度(像素, 默认为300px,最小允许 175px)。仅当 input_panel_fixed=True 时可用。

  • input_auto_focus (bool): 输入栏是否自动获取输入焦点,默认为 True

  • output_max_width (str): 页面内容区域的最大宽度(像素或百分比,例如: '1080px', '80%'. 默认为 '880px'

Example:

set_env(title='Awesome PyWebIO!!', output_animation=False)

在 1.4 版更改: Added the output_max_width parameter

pywebio.session.go_app(name, new_window=True)[源代码]

在同一PyWebIO应用的不同服务之间跳转。仅在PyWebIO Server模式下可用

参数
  • name (str) – 目标 PyWebIO 任务名

  • new_window (bool) – 是否在新窗口打开,默认为 True

参见: Server 模式

pywebio.session.info

表示会话信息的对象,属性有:

  • user_agent : 表示用户浏览器信息的对象,属性有

    • is_mobile (bool): 用户使用的设备是否为手机 (比如 iPhone, Android phones, Blackberry, Windows Phone 等设备)

    • is_tablet (bool): 用户使用的设备是否为平板 (比如 iPad, Kindle Fire, Nexus 7 等设备)

    • is_pc (bool): 用户使用的设备是否为桌面电脑 (比如运行 Windows, OS X, Linux 的设备)

    • is_touch_capable (bool): 用户使用的设备是否支持触控

    • browser.family (str): 浏览器家族. 比如 ‘Mobile Safari’

    • browser.version (tuple): 浏览器版本元组. 比如 (5, 1)

    • browser.version_string (str): 浏览器版本字符串. 比如 ‘5.1’

    • os.family (str): 操作系统家族. 比如 ‘iOS’

    • os.version (tuple): 操作系统版本元组. 比如 (5, 1)

    • os.version_string (str): 操作系统版本字符串. 比如 ‘5.1’

    • device.family (str): 设备家族. 比如 ‘iPhone’

    • device.brand (str): 设备品牌. 比如 ‘Apple’

    • device.model (str): 设备型号. 比如 ‘iPhone’

  • user_language (str): 用户操作系统使用的语言. 比如 'zh-CN'

  • server_host (str): 当前会话的服务器host,包含域名和端口,端口为80时可以被省略

  • origin (str): 当前用户的页面地址. 包含 协议、主机、端口 部分. 比如 'http://localhost:8080' . 可能为空,但保证当用户的页面地址不在当前服务器下(即 主机、端口部分和 server_host 不一致)时有值.

  • user_ip (str): 用户的ip地址.

  • backend (str): 当前PyWebIO使用的后端Server实现. 可能出现的值有 'tornado' , 'flask' , 'django' , 'aiohttp' , 'starlette'.

  • protocol (str): PyWebIO服务器与浏览器之间的通信协议。可能的值为 'websocket''http'

  • request (object): 创建当前会话时的Web请求对象. 根据PyWebIO使用的后端Server不同,request 的类型也不同:

会话信息对象的 user_agent 属性是通过 user-agents 库进行解析生成的。参见 https://github.com/selwin/python-user-agents#usage

在 1.2 版更改: Added the protocol attribute.

Example:

import json
from pywebio.session import info as session_info

put_code(json.dumps({
    k: str(getattr(session_info, k))
    for k in ['user_agent', 'user_language', 'server_host',
              'origin', 'user_ip', 'backend', 'protocol', 'request']
}, indent=4), 'json')
class pywebio.session.coroutinebased.TaskHandler(close, closed)[源代码]

协程任务句柄

See also: run_async()

close()[源代码]

关闭协程任务

closed()bool[源代码]

任务是否关闭

pywebio.session.hold()[源代码]

保持会话,直到用户关闭浏览器。

注意

Since PyWebIO v1.4, in server mode, it’s no need to call this function manually, PyWebIO will automatically hold the session for you when needed. The only case to use it is to prevent the application from exiting in script mode.

如果你还在使用旧版本的PyWebIO(强烈建议你升级版本),这是 hold() 函数旧版本的文档:

在PyWebIO会话结束后,页面和服务端的连接便会断开, 页面上需要和服务端通信才可实现的功能(比如:下载通过 put_file() 输出的文件, put_buttons() 按钮回调)便无法使用。 可以在任务函数末尾处调用 hold() 函数来将会话保持,这样在用户关闭浏览器页面前,会话将一直保持连接。

pywebio.session.run_async(coro_obj)[源代码]

异步运行协程对象。协程中依然可以调用 PyWebIO 交互函数。

run_async() 仅能在 基于协程 的会话上下文中调用

参数

coro_obj – 协程对象

返回

TaskHandle 实例。 通过 TaskHandle 可以查询协程运行状态和关闭协程。

参见:协程会话的并发

pywebio.session.run_asyncio_coroutine(coro_obj)[源代码]

若会话线程和运行asyncio事件循环的线程不是同一个线程,需要用 run_asyncio_coroutine() 来运行asyncio中的协程。

仅能在 基于协程 的会话上下文中调用。

参数

coro_objasyncio 库中的协程对象

Example:

async def app():
    put_text('hello')
    await run_asyncio_coroutine(asyncio.sleep(1))
    put_text('world')

pywebio.platform.flask.start_server(app)

pywebio.platform — 应用部署

platform 模块提供了以不同方式部署PyWebIO应用的支持。

Directory Deploy

可以使用 path_deploy()path_deploy_http() 来从一个目录中部署PyWebIO应用。该目录下的python文件需要包含一个名为 main 的函数作为PyWebIO应用。服务端会根据用户访问的URL来确定需要加载的文件并从中读取PyWebIO应用来运行。

用户无法访问该目录下以下划线开始的文件和目录。

例如,给定如下文件结构:

.
├── A
│   └── a.py
├── B
│   └── b.py
└── c.py

三个python文件都含有 main PyWebIO应用函数。

如果使用以上路径调用 path_deploy() ,你可以通过 URL http://<host>:<port>/A/b` 来访问 b.py 文件中的PyWebIO应用。若文件在运行 path_deploy() 之后被修改,可以使用 reload URL参数来重载文件: http://<host>:<port>/A/b?reload

你还可以使用 pywebio-path-deploy 命令来启动一个和 path_deploy() 效果一样的server。关于命令的更多信息请查阅命令帮助: pywebio-path-deploy --help

pywebio.platform.path_deploy(base, port=0, host='', index=True, static_dir=None, reconnect_timeout=0, cdn=True, debug=False, allowed_origins=None, check_origin=None, max_payload_size='200M', **tornado_app_settings)[源代码]

从一个路径中部署PyWebIO应用

服务端使用WebSocket协议与浏览器进行通讯。

参数
  • base (str) – 用于加载PyWebIO应用的根目录

  • port (int) – 服务器监听的端口

  • host (str) – 服务绑定的地址

  • index (bool/callable) – 当请求一个文件夹时是否显示默认的索引页面,默认为 Trueindex 也可以为一个函数来自定义索引页面,其接收请求的文件夹路径作为参数,返回页面HTML字符串。你可以在文件夹中创建一个 index.py PyWebIO应用文件来重写文件夹的索引页。

  • static_dir (str) – 应用静态文件目录。目录下的文件可以通过 http://<host>:<port>/static/files 访问。例如 static_dir 路径下存在文件 A/B.jpg ,则其URL为 http://<host>:<port>/static/A/B.jpg

  • reconnect_timeout (int) – 客户端重连超时时间(秒)。客户端若意外与服务端断开连接,在 reconnect_timeout 秒内可以重新连接并自动恢复会话。

剩余参数的详细说明见 pywebio.platform.tornado.start_server() 的同名参数。

pywebio.platform.path_deploy_http(base, port=0, host='', index=True, static_dir=None, cdn=True, debug=False, allowed_origins=None, check_origin=None, session_expire_seconds=None, session_cleanup_interval=None, max_payload_size='200M', **tornado_app_settings)[源代码]

从一个路径中部署PyWebIO应用

服务端使用HTTP协议与浏览器进行通讯。

关于 path_deploy_http()base, port, host, index, static_dir 参数的详细说明见 pywebio.platform.path_deploy() 的同名参数。

剩余参数的详细说明见 pywebio.platform.tornado_http.start_server() 的同名参数。

Application Deploy

start_server() 函数可以启动一个Web服务器来将PyWebIO应用作为Web服务运行。

webio_handler()webio_view() 函数用于将PyWebIO应用整合到现有的Python Web项目中。

wsgi_app()asgi_app() 用于获取运行PyWebIO应用的 WSGI 或 ASGI app。很适合当你不想使用Web框架内置的server来启动服务的情况。比如,你想使用其他WSGI server来启动应用,或者你正在将应用部署到一些云环境中。目前仅在Flask、Django 和 FastApi后端中支持 wsgi_app() / asgi_app()

在 1.1 版更改: Added the cdn parameter in start_server(), webio_handler() and webio_view().

在 1.2 版更改: Added the static_dir parameter in start_server().

在 1.3 版更改: Added the wsgi_app() and asgi_app().

Tornado相关

服务端可以通过两种协议(WebSocket 和 HTTP)来与用户浏览器通信。

WebSocket
pywebio.platform.tornado.start_server(applications: Union[Callable[], None], List[Callable[], None]], Dict[str, Callable[], None]]], port: int = 0, host: str = '', debug: bool = False, cdn: Union[bool, str] = True, static_dir: Optional[str] = None, remote_access: bool = False, reconnect_timeout: int = 0, allowed_origins: Optional[List[str]] = None, check_origin: Optional[Callable[[str], bool]] = None, auto_open_webbrowser: bool = False, max_payload_size: Union[int, str] = '200M', **tornado_app_settings)[源代码]

启动一个 Tornado server 将PyWebIO应用作为Web服务提供。

Tornado server 使用WebSocket协议与浏览器进行通讯。

Tornado为PyWebIO应用的默认后端Server,可以直接使用 from pywebio import start_server 导入。

参数
  • applications (list/dict/callable) –

    PyWebIO应用. 可以是任务函数或者任务函数的字典或列表。详细用法参见 使用start_server()部署多应用

    任务函数为协程函数时,使用 基于协程的会话实现 ;任务函数为普通函数时,使用基于线程的会话实现。

  • port (int) – 服务监听的端口。设置为 0 时,表示自动选择可用端口。

  • host (str) – 服务绑定的地址。 host 可以是IP地址或者为hostname。如果为hostname,服务会监听所有与该hostname关联的IP地址。 通过设置 host 为空字符串或 None 来将服务绑定到所有可用的地址上。

  • debug (bool) – 是否开启Tornado Server的debug模式,开启后,代码发生修改后服务器会自动重启。 详情请参阅 tornado 文档

  • cdn (bool/str) – 是否从CDN加载前端静态资源,默认为 True 。支持传入自定义的URL来指定静态资源的部署地址

  • static_dir (str) – 应用静态文件目录。目录下的文件可以通过 http://<host>:<port>/static/files 访问。例如 static_dir 路径下存在文件 A/B.jpg ,则其URL为 http://<host>:<port>/static/A/B.jpg

  • remote_access (bool) – 是否开启远程接入的功能。开启后,你将得到一个你当前应用的临时公网访问地址,其他人可以通过此地址访问你的应用。

  • auto_open_webbrowser (bool) – 当服务启动后,是否自动打开浏览器来访问服务。(该操作需要操作系统支持)

  • reconnect_timeout (int) – 客户端重连超时时间(秒)。客户端若意外与服务端断开连接,在 reconnect_timeout 秒内可以重新连接并自动恢复会话。

  • allowed_origins (list) –

    除当前域名外,服务器还允许的请求的来源列表。来源包含协议、域名和端口部分,允许使用 Unix shell 风格的匹配模式:

    • * 为通配符

    • ? 匹配单个字符

    • [seq] 匹配seq中的任何字符

    • [!seq] 匹配任何不在seq中的字符

    比如 https://*.example.com*://*.example.com

    全部规则参见 Python文档

  • check_origin (callable) – 请求来源检查函数。接收请求来源(包含协议、域名和端口部分)字符串作为参数, 返回 True/False 指示服务器接受/拒绝该请求。若设置了 check_originallowed_origins 参数将被忽略

  • auto_open_webbrowser – 当服务启动后,是否自动打开浏览器来访问服务。(该操作需要操作系统支持)

  • max_payload_size (int/str) – Tornado Server可以接受的最大websocket消息的大小。超过 max_payload_size (默认 200MB) 的消息会被拒绝接受。 max_payload_size 可以是整形表示的字节数或以 K / M / G 结尾的字符串,比如: 500, '40K', '3M'

  • tornado_app_settings – 传递给 tornado.web.Application 构造函数的额外的关键字参数 可设置项参考: https://www.tornadoweb.org/en/stable/web.html#tornado.web.Application.settings

pywebio.platform.tornado.webio_handler(applications, cdn=True, reconnect_timeout=0, allowed_origins=None, check_origin=None)[源代码]

获取在Tornado中运行PyWebIO应用的RequestHandler类。RequestHandler类基于WebSocket协议与浏览器进行通讯。

关于各参数的详细说明见 pywebio.platform.tornado.start_server() 的同名参数。

HTTP
pywebio.platform.tornado_http.start_server(applications, port=8080, host='', debug=False, cdn=True, static_dir=None, allowed_origins=None, check_origin=None, auto_open_webbrowser=False, session_expire_seconds=None, session_cleanup_interval=None, max_payload_size='200M', **tornado_app_settings)[源代码]

启动一个 Tornado server 将PyWebIO应用作为Web服务提供。

服务端使用HTTP协议与浏览器进行通讯。

参数
  • session_expire_seconds (int) – 会话过期时间,单位为秒(默认60秒)。若 session_expire_seconds 秒内没有收到客户端的请求,则认为会话过期。

  • session_cleanup_interval (int) – 会话清理间隔,单位为秒(默认12秒)。服务端会周期性清理过期的会话,释放会话占用的资源。

  • max_payload_size (int/str) – Tornado Server可以接受的最大单个HTTP请求的大小

剩余参数的详细说明见 pywebio.platform.tornado.start_server() 的同名参数。

1.2 新版功能.

pywebio.platform.tornado_http.webio_handler(applications, cdn=True, session_expire_seconds=None, session_cleanup_interval=None, allowed_origins=None, check_origin=None)[源代码]

获取在Tornado中运行PyWebIO应用的RequestHandler类。RequestHandler类基于HTTP协议与浏览器进行通讯。

关于各参数的详细说明见 pywebio.platform.tornado_http.start_server() 的同名参数。

1.2 新版功能.

Flask support

使用Flask后端作为PyWebIO应用Server时,需要您自行安装Flask,并确保版本大于等于 0.10 。 可通过以下命令安装:

pip3 install -U flask>=0.10
pywebio.platform.flask.webio_view(applications, cdn=True, session_expire_seconds=None, session_cleanup_interval=None, allowed_origins=None, check_origin=None)[源代码]

获取在Flask中运行PyWebIO任务的视图函数。基于http请求与前端页面进行通讯

关于各参数的详细说明见 pywebio.platform.flask.start_server() 的同名参数。

pywebio.platform.flask.wsgi_app(applications, cdn=True, static_dir=None, allowed_origins=None, check_origin=None, session_expire_seconds=None, session_cleanup_interval=None, max_payload_size='200M')[源代码]

将PyWebIO应用转换为Flask WSGI 应用

关于各参数的详细说明见 pywebio.platform.flask.start_server() 的同名参数。

pywebio.platform.flask.start_server(applications, port=8080, host='', cdn=True, static_dir=None, remote_access=False, allowed_origins=None, check_origin=None, session_expire_seconds=None, session_cleanup_interval=None, debug=False, max_payload_size='200M', **flask_options)[源代码]

启动一个 Flask server 将PyWebIO应用作为Web服务提供。

参数
  • session_expire_seconds (int) – 会话过期时间,单位为秒(默认600秒)。若 session_expire_seconds 秒内没有收到客户端的请求,则认为会话过期。

  • session_cleanup_interval (int) – 会话清理间隔,单位为秒(默认300秒)。服务端会周期性清理过期的会话,释放会话占用的资源。

  • debug (bool) – 是否开启Flask Server的debug模式,开启后,代码发生修改后服务器会自动重启。

  • max_payload_size (int/str) – Flask Server可以接受的最大单个HTTP请求的大小

  • flask_options – 传递给 flask.Flask.run 函数的额外的关键字参数 可设置项参考: https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.run

关于各参数的详细说明见 pywebio.platform.tornado.start_server() 的同名参数

Django support

使用Django后端作为PyWebIO应用Server时,需要您自行安装Django,并确保版本大于等于 2.2 。 可通过以下命令安装:

pip3 install -U django>=2.2
pywebio.platform.django.webio_view(applications, cdn=True, session_expire_seconds=None, session_cleanup_interval=None, allowed_origins=None, check_origin=None)[源代码]

获取在django中运行PyWebIO任务的视图函数。 基于http请求与前端进行通讯

关于各参数的详细说明见 pywebio.platform.flask.webio_view() 的同名参数。

pywebio.platform.django.wsgi_app(applications, cdn=True, static_dir=None, allowed_origins=None, check_origin=None, session_expire_seconds=None, session_cleanup_interval=None, debug=False, max_payload_size='200M', **django_options)[源代码]

将PyWebIO应用转换为Django WSGI 应用

关于各参数的详细说明见 pywebio.platform.django.start_server() 的同名参数。

pywebio.platform.django.start_server(applications, port=8080, host='', cdn=True, static_dir=None, remote_access=False, allowed_origins=None, check_origin=None, session_expire_seconds=None, session_cleanup_interval=None, debug=False, max_payload_size='200M', **django_options)[源代码]

启动一个 Django server 将PyWebIO应用作为Web服务提供。

参数

剩余参数的详细说明见 pywebio.platform.flask.start_server() 的同名参数。

aiohttp support

使用aiohttp后端作为PyWebIO应用Server时,需要您自行安装aiohttp,并确保版本大于等于 3.1 。 可通过以下命令安装:

pip3 install -U aiohttp>=3.1
pywebio.platform.aiohttp.webio_handler(applications, cdn=True, reconnect_timeout=0, allowed_origins=None, check_origin=None, max_payload_size='200M', websocket_settings=None)[源代码]

Get the Request Handler coroutine for running PyWebIO applications in aiohttp. The handler communicates with the browser by WebSocket protocol.

The arguments of webio_handler() have the same meaning as for pywebio.platform.aiohttp.start_server()

返回

aiohttp Request Handler

pywebio.platform.aiohttp.start_server(applications, port=0, host='', debug=False, cdn=True, static_dir=None, remote_access=False, reconnect_timeout=0, allowed_origins=None, check_origin=None, auto_open_webbrowser=False, max_payload_size='200M', websocket_settings=None, **aiohttp_settings)[源代码]

Start a aiohttp server to provide the PyWebIO application as a web service.

参数

剩余参数的详细说明见 pywebio.platform.tornado.start_server() 的同名参数。

FastAPI/Starlette support

当使用FastAPI/Starlette作为PyWebIO的后端server时,你需要手动安装 fastapistarlette ,另外还需要安装一些其他的依赖库,可以使用以下命令安装:

pip3 install -U fastapi starlette uvicorn aiofiles websockets
pywebio.platform.fastapi.webio_routes(applications, cdn=True, reconnect_timeout=0, allowed_origins=None, check_origin=None)[源代码]

获取在FastAPI/Starlette中运行PyWebIO的路由组件。

服务端使用WebSocket协议与浏览器进行通讯。

关于各参数的详细说明见 pywebio.platform.fastapi.start_server() 的同名参数。

1.3 新版功能.

返回

FastAPI/Starlette routes

pywebio.platform.fastapi.asgi_app(applications, cdn=True, reconnect_timeout=0, static_dir=None, debug=False, allowed_origins=None, check_origin=None)[源代码]

将PyWebIO应用转换为starlette/Fastapi ASGI应用

如果你需要自己托管静态文件,请使用 pywebio.platform.fastapi.webio_routes()

关于各参数的详细说明见 pywebio.platform.fastapi.start_server() 的同名参数。

Example

FastAPI.mount() 一起使用以将 pywebio 作为子应用包含到现有的 Starlette/FastAPI 应用程序中:

from fastapi import FastAPI
from pywebio.platform.fastapi import asgi_app
from pywebio.output import put_text
app = FastAPI()
subapp = asgi_app(lambda: put_text("hello from pywebio"))
app.mount("/pywebio", subapp)
Returns

Starlette/Fastapi ASGI app

1.3 新版功能.

pywebio.platform.fastapi.start_server(applications, port=0, host='', cdn=True, reconnect_timeout=0, static_dir=None, remote_access=False, debug=False, allowed_origins=None, check_origin=None, auto_open_webbrowser=False, max_payload_size='200M', **uvicorn_settings)[源代码]

启动一个 FastAPI/Starlette server 将PyWebIO应用作为Web服务提供。

参数
  • debug (bool) – 发生异常时是否打印调用栈。

  • uvicorn_settings – 传递给 uvicorn.run() 的额外关键字参数 可设置项参考: https://www.uvicorn.org/settings/

剩余参数的详细说明见 pywebio.platform.tornado.start_server() 的同名参数。

1.3 新版功能.

其他

pywebio.config(*, title=None, description=None, theme=None, js_code=None, js_file=[], css_style=None, css_file=[], manifest=True)[源代码]

PyWebIO应用配置

参数
  • title (str) – 应用标题

  • description (str) – 应用简介

  • theme (str) –

    主题设置。可用主题有: dark, sketchy, minty, yeti 。同样可以使用环境变量 PYWEBIO_THEME 来设置主题(有更高优先级)。

    主题预览

    None

    dark主题更改自 bootstrap-dark , sketchy, minty和yeti 主题来自 bootswatch

  • js_code (str) – 需要注入到页面上的Javascript代码

  • js_file (str/list) – 需要添加到页面上的Javascript脚本文件,可以是文件的URL或URL列表。

  • css_style (str) – 需要注入到页面上的CSS样式规则。

  • css_file (str/list) – 需要添加到页面上的CSS样式文件,可以是文件的URL或URL列表。

  • manifest (bool/dict) –

    Web application manifest configuration. This feature allows you to add a shortcut to the home screen of your mobile device, and launch the app like a native app. If set to True, the default manifest will be used. You can also specify the manifest content in dict. If False, the manifest will be disabled.

    None

    Currently, the icons field of the manifest is not supported. Instead, you can use the icon field to specify the icon url.

config() 可以通过两种方式使用:直接调用或作为装饰器使用。如果直接调用 config() ,将会作用于全局;如果使用装饰器,配置进将作用于被装饰的PyWebIO应用函数:

config(title="My application")  # global configuration

@config(css_style="* { color:red }")  # only works on this application
def app():
    put_text("hello PyWebIO")

注解

The configuration will affect all sessions

titledescription 被用来设置SEO(在被搜索引擎索引时提供的网页信息)。如果没有提供 titledescription ,PyWebIO默认会将任务函数的 函数注释 作为SEO信息:

def app():
    """应用标题

    应用简介...
    (应用简介和标题之间使用一个空行分隔)
    """
    pass

以上代码等价于:

@config(title="Application title", description="Application description...")
def app():
    pass

1.4 新版功能.

在 1.5 版更改: add theme parameter

pywebio.platform.run_event_loop(debug=False)[源代码]

运行 asyncio 事件循环

See also: Integration coroutine-based session with Web framework

参数

debug – Set the debug mode of the event loop. See also: https://docs.python.org/3/library/asyncio-dev.html#asyncio-debug-mode

pywebio.pin — 持续性输入

pin == Persistent input == Pinning input widget to the page

Overview

我们已经知道,PyWebIO中的输入函数是阻塞式的,输入表单会在成功提交后被销毁。在大多数场景下,使用这种方式接收用户输入已经够用了。但在一些场景下,你或许希望输入表单在提交后不消失,并且可以继续接收输入。

所以,PyWebIO提供了 pin 模块来实现持续性输入。

pin 模块主要有3部分内容:

首先, pin 模块提供了一些 pin 组件(widgets)。Pin 组件和 pywebio.output 模块中的输出组件并没有什么不同,只不过它还可以接收输入。

以下代码输出了一个最基本的文本框pin组件:

put_input('input', label='This is a input widget')

实际上, pin 组件函数的调用方式和输出函数是一致的,你可以将其作为组合输出的一部分, 也可以将其输出到某个scope中:

put_row([
    put_input('input'),
    put_select('select', options=['A', 'B', 'C'])
])

with use_scope('search-area'):
    put_input('search', placeholder='Search')

然后,你可以使用 pin 对象来获取pin组件的值:

put_input('pin_name')
put_buttons(['Get Pin Value'], lambda _: put_text(pin.pin_name))

Pin组件函数的第一个参数为pin组件的 name 。你可以使用 pin 对象的同名属性来获取对应pin组件的当前值。

另外, pin 对象同样支持以索引的方式获取pin组件的值,即:

pin['pin_name'] == pin.pin_name

Pin模块中还有两个有用的函数: pin_wait_change()pin_update()

由于pin组件输出函数是非阻塞的, 所以使用 pin_wait_change() 来等待一组pin组件的值发生变化,它是一个阻塞式函数。

pin_update() 可以用来更新pin组件的输出属性。

Pin widgets

Each pin widget function corresponds to an input function of input module.

Pin组件函数支持大多数对应的输入函数的参数。这里列举了两者之间的一些不同:

  • Pin组件函数的第一个参数始终是Pin组件的 name ,且当输出了同名的pin组件时,旧的pin组件会不可用。

  • Pin functions don’t support the on_change and validate callbacks, and the required parameter. (There is a pin_on_change() function as an alternative to on_change)

  • Pin组件函数多了用于输出控制的 scopeposition 参数。

pywebio.pin.put_input(name: str, type: str = 'text', *, label: str = '', value: Optional[str] = None, placeholder: Optional[str] = None, readonly: Optional[bool] = None, datalist: Optional[List[str]] = None, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个文本输入组件。参见 pywebio.input.input()

pywebio.pin.put_textarea(name: str, *, label: str = '', rows: int = 6, code: Optional[Union[bool, Dict]] = None, maxlength: Optional[int] = None, minlength: Optional[int] = None, value: Optional[str] = None, placeholder: Optional[str] = None, readonly: Optional[bool] = None, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个文本域输入组件。参见 pywebio.input.textarea()

pywebio.pin.put_select(name: str, options: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, *, label: str = '', multiple: Optional[bool] = None, value: Optional[Union[List, str]] = None, native: Optional[bool] = None, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个下拉选择输入组件。参见 pywebio.input.select()

注解

Unlike pywebio.input.select(), when multiple=True and the user is using PC/macOS, put_select() will use bootstrap-select by default. Setting native=True will force PyWebIO to use native select component on all platforms and vice versa.

pywebio.pin.put_checkbox(name: str, options: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, *, label: str = '', inline: Optional[bool] = None, value: Optional[List] = None, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个多选框组件。参见 pywebio.input.checkbox()

pywebio.pin.put_radio(name: str, options: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, *, label: str = '', inline: Optional[bool] = None, value: Optional[str] = None, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个单选按钮组件。参见 pywebio.input.radio()

pywebio.pin.put_slider(name: str, *, label: str = '', value: Union[int, float] = 0, min_value: Union[int, float] = 0, max_value: Union[int, float] = 100, step: int = 1, required: Optional[bool] = None, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一个滑块输入组件。参见 pywebio.input.slider()

pywebio.pin.put_actions(name: str, *, label: str = '', buttons: Optional[List[Union[Dict[str, Any], Tuple, List, str]]] = None, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

输出一组action按钮。参见 pywebio.input.actions()

不像 actions()` 函数,``put_actions() 不会提交任何表单,它只会设置pin组件的值。 put_actions() 只接受 ‘submit’ 类型的按钮。

1.4 新版功能.

pywebio.pin.put_file_upload(name: str, *, label: str = '', accept: Optional[Union[List, str]] = None, placeholder: str = 'Choose file', multiple: bool = False, max_size: Union[int, str] = 0, max_total_size: Union[int, str] = 0, help_text: Optional[str] = None, scope: Optional[str] = None, position: int = - 1)pywebio.io_ctrl.Output[源代码]

Output a file uploading widget. Refer to: pywebio.input.file_upload()

Pin utils

pywebio.pin.pin

获取与设置Pin组件的值

You can use attribute or key index of pin object to get the current value of a pin widget. By default, when accessing the value of a widget that does not exist, it returns None instead of throwing an exception. You can enable the error raising by pin.use_strict() method.

还可以使用 pin 对象设置pin组件的值:

put_input('counter', type='number', value=0)

while True:
    pin.counter = pin.counter + 1  # Equivalent to: pin['counter'] = pin['counter'] + 1
    time.sleep(1)

注:当使用 基于协程的会话 时,你需要使用 await pin.name (或 await pin['name']) 语法来获取pin组件的值。

Use pin.pin.use_strict() to enable strict mode for getting pin widget value. An AssertionError will be raised when try to get value of pin widgets that are currently not in the page.

pywebio.pin.pin_wait_change(*names, timeout: Optional[int] = None)[源代码]

pin_wait_change() 监听一组pin组件,当其中任意一个的值发生变化后,函数返回发生变化的组件的 name 和值。

参数
  • names (str) – Pin组件 name 列表

  • timeout (int/None) – 当 timeout 为正数时, pin_wait_change() 会最多阻塞 timeout 秒然后返回 None 如果这段时间内监听的pin组件的值没有发生变化的话。 将 timeout 设置为 None (默认)来关闭超时。

Return dict/None

{"name": 发生变化的pin组件的name, "value": 发生变化的pin组件的当前值} , 当超时发生后,返回 None

Example:

put_input('a', type='number', value=0)
put_input('b', type='number', value=0)

while True:
    changed = pin_wait_change('a', 'b')
    with use_scope('res', clear=True):
        put_code(changed)
        put_text("a + b = %s" % (pin.a + pin.b))

这里 有一个使用 pin_wait_change() 实现markdown实时预览的demo。

注:使用 pin 对象或 pin_update() 更新pin组件的值不会引发 pin_wait_change() 返回

当使用 基于协程的会话 时,你需要使用 await pin_wait_change() 语法来调用此函数。

pywebio.pin.pin_update(name: str, **spec)[源代码]

更新pin组件的输出属性。

参数
  • name (str) – 目标pin组件的 name

  • spec – 需要被更新的pin组件的参数。注意以下参数无法被更新: type, name, code, multiple

pywebio.pin.pin_on_change(name: str, onchange: Optional[Callable[[Any], None]] = None, clear: bool = False, init_run: bool = False, **callback_options)[源代码]

Bind a callback function to pin widget, the function will be called when user change the value of the pin widget.

The onchange callback is invoked with one argument, the changed value of the pin widget. You can bind multiple functions to one pin widget, those functions will be invoked sequentially (default behavior, can be changed by clear parameter).

参数
  • name (str) – pin widget name

  • onchange (callable) – callback function

  • clear (bool) – whether to clear the previous callbacks bound to this pin widget. If you just want to clear callbacks and not set new callback, use pin_on_change(name, clear=True).

  • init_run (bool) – whether to run the onchange callback once immediately before the pin widget changed. This parameter can be used to initialize the output.

  • callback_options – Other options of the onclick callback. Refer to the callback_options parameter of put_buttons()

1.6 新版功能.

高级特性

本部分介绍PyWebIO的高级特性。

使用start_server()启动多应用

start_server() 接收一个函数作为PyWebIO应用,另外, start_server() 还支持传入函数列表或字典,从而启动多个PyWebIO应用,应用之间可以通过 go_app()put_link() 进行跳转:

def task_1():
    put_text('task_1')
    put_buttons(['Go task 2'], [lambda: go_app('task_2')])

def task_2():
    put_text('task_2')
    put_buttons(['Go task 1'], [lambda: go_app('task_1')])

def index():
    put_link('Go task 1', app='task_1')  # Use `app` parameter to specify the task name
    put_link('Go task 2', app='task_2')

# equal to `start_server({'index': index, 'task_1': task_1, 'task_2': task_2})`
start_server([index, task_1, task_2])

start_server() 的第一个参数的类型为字典时,字典键为应用名,类型为列表时,函数名为应用名。

可以通过 app URL参数选择要访问的应用(例如使用 http://host:port/?app=foo 来访问 foo 应用), 为提供了 app URL参数时默认使用运行 index 应用,当 index 应用不存在时,PyWebIO会提供一个默认的索引页作为 index 应用。

与Web框架整合

可以将PyWebIO应用集成到现有的Python Web项目中,PyWebIO应用与Web项目共用一个Web框架。目前支持与Flask、Tornado、Django、aiohttp和FastAPI(Starlette) Web框架的集成。

不同Web框架的集成方法如下:

使用 pywebio.platform.tornado.webio_handler() 来获取在Tornado中运行PyWebIO应用的 WebSocketHandler 类:

import tornado.ioloop
import tornado.web
from pywebio.platform.tornado import webio_handler

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", MainHandler),
        (r"/tool", webio_handler(task_func)),  # `task_func` is PyWebIO task function
    ])
    application.listen(port=80, address='localhost')
    tornado.ioloop.IOLoop.current().start()

以上代码将 PyWebIO 应用的 WebSocketHandler 绑定到了 /tool 路径下。 启动Tornado后,访问 http://localhost/tool 即可打开PyWebIO应用。

注意

当使用Tornado后端时,PyWebIO使用WebSocket协议和浏览器进行通讯,如果你的Tornado应用处在反向代理(比如Nginx)之后,可能需要特别配置反向代理来支持WebSocket协议,这里 有一个Nginx配置WebSocket的例子。

Notes

生产环境部署

在生产环境中,你可能会使用一些 WSGI/ASGI 服务器(如 uWSGI、Gunicorn、Uvicorn)部署 Web 应用程序。由于 PyWebIO 应用程序会在进程中存储会话状态,当使用基于 HTTP 的会话(使用Flask 和 Django后端时)并生成多个进程来处理请求时,请求可能会被分发到错误的进程中。因此,在使用基于 HTTP 的会话时,只能启动一个进程来处理请求。

如果仍然希望使用多进程来提高并发,一种方式是使用 Uvicorn+FastAPI,或者你也可以启动多个Tornado/aiohttp进程,并在它们之前添加外部的负载均衡软件(如 HAProxy 或 nginx)。这些后端使用 WebSocket 协议与浏览器进行通信,所以不存在上述问题。

PyWebIO静态资源的托管

PyWebIO默认使用CDN来获取前端的静态资源,如果要将PyWebIO应用部署到离线环境中,需要自行托管静态文件, 并将 webio_view()webio_handler()cdn 参数设置为 False

cdn=False 时需要将静态资源托管在和PyWebIO应用同级的目录下。 同时,也可以通过 cdn 参数直接设置PyWebIO静态资源的URL目录。

PyWebIO的静态文件的路径保存在 pywebio.STATIC_PATH 中,可使用命令 python3 -c "import pywebio; print(pywebio.STATIC_PATH)" 将其打印出来。

注解

使用 start_server() 启动的应用,如果将 cdn 参数设置为 False ,会自动启动一个本地的静态资源托管服务,无需手动托管。

基于协程的会话

在大部分情况下,你并不需要使用基于协程的会话。PyWebIO中所有仅用于协程会话的函数或方法都在文档中均有特别说明。

PyWebIO的会话实现默认是基于线程的,用户每打开一个和服务端的会话连接,PyWebIO会启动一个线程来运行任务函数。 除了基于线程的会话,PyWebIO还提供了基于协程的会话。基于协程的会话接受协程函数作为任务函数。

基于协程的会话为单线程模型,所有会话都运行在一个线程内。对于IO密集型的任务,协程比线程占用更少的资源同时又拥有媲美于线程的性能。 另外,协程的上下文切换具有可预测性,能够减少程序同步与加锁的需要,可以有效避免大多数临界区问题。

使用协程会话

要使用基于协程的会话,需要使用 async 关键字将任务函数声明为协程函数,并使用 await 语法调用PyWebIO输入函数:

 from pywebio.input import *
 from pywebio.output import *
 from pywebio import start_server

 async def say_hello():
     name = await input("what's your name?")
     put_text('Hello, %s' % name)

 start_server(say_hello, auto_open_webbrowser=True)

在协程任务函数中,也可以使用 await 调用其他协程或标准库 asyncio 中的可等待对象( awaitable objects ):

 import asyncio
 from pywebio import start_server

 async def hello_word():
     put_text('Hello ...')
     await asyncio.sleep(1)  # await awaitable objects in asyncio
     put_text('... World!')

 async def main():
     await hello_word()  # await coroutine
     put_text('Bye, bye')

 start_server(main, auto_open_webbrowser=True)

注意

在基于协程的会话中, pywebio.input 模块中的定义输入函数都需要使用 await 语法来获取返回值,忘记使用 await 将会是在使用基于协程的会话时常出现的错误。

其他在协程会话中也需要使用 await 语法来进行调用函数有:

警告

虽然PyWebIO的协程会话兼容标准库 asyncio 中的 awaitable objects ,但 asyncio 库不兼容PyWebIO协程会话中的 awaitable objects .

也就是说,无法将PyWebIO中的 awaitable objects 传入 asyncio 中的接受 awaitable objects 作为参数的函数中,比如如下调用是 不被支持的

await asyncio.shield(pywebio.input())
await asyncio.gather(asyncio.sleep(1), pywebio.session.eval_js('1+1'))
task = asyncio.create_task(pywebio.input())
协程会话的并发

在基于协程的会话中,你可以启动线程,但是无法在其中调用PyWebIO交互函数( register_thread() 在协程会话中不可用)。 但你可以使用 run_async(coro) 来异步执行一个协程对象,新协程内可以使用PyWebIO交互函数:

 from pywebio import start_server
 from pywebio.session import run_async

 async def counter(n):
     for i in range(n):
         put_text(i)
         await asyncio.sleep(1)

 async def main():
     run_async(counter(10))
     put_text('Main coroutine function exited.')


 start_server(main, auto_open_webbrowser=True)

run_async(coro) 返回一个 TaskHandler ,通过该 TaskHandler 可以查询协程运行状态和关闭协程。

会话的结束

和基于线程的会话一样,当用户关闭浏览器页面后,会话也随之关闭。

浏览器页面关闭后,当前会话内还未返回的PyWebIO输入函数调用将抛出 SessionClosedException 异常,之后对于PyWebIO交互函数的调用将会产生 SessionNotFoundExceptionSessionClosedException 异常。

协程会话也同样支持使用 defer_call(func) 来设置会话结束时需要调用的函数。

协程会话与Web框架集成

基于协程的会话同样可以与Web框架进行集成,只需要在原来传入任务函数的地方改为传入协程函数即可。

但当前在使用基于协程的会话集成进Flask或Django时,存在一些限制:

一是协程函数内还无法直接通过 await 直接等待asyncio库中的协程对象,目前需要使用 run_asyncio_coroutine() 进行包装。

二是,在启动Flask/Django这类基于线程的服务器之前需要启动一个单独的线程来运行事件循环。

使用基于协程的会话集成进Flask的示例:

 import asyncio
 import threading
 from flask import Flask, send_from_directory
 from pywebio import STATIC_PATH
 from pywebio.output import *
 from pywebio.platform.flask import webio_view
 from pywebio.platform import run_event_loop
 from pywebio.session import run_asyncio_coroutine

 async def hello_word():
     put_text('Hello ...')
     await run_asyncio_coroutine(asyncio.sleep(1))  # can't just "await asyncio.sleep(1)"
     put_text('... World!')

 app = Flask(__name__)
 app.add_url_rule('/hello', 'webio_view', webio_view(hello_word),
                             methods=['GET', 'POST', 'OPTIONS'])

 # thread to run event loop
 threading.Thread(target=run_event_loop, daemon=True).start()
 app.run(host='localhost', port=80)

最后,使用PyWebIO编写的协程函数不支持Script模式,总是需要使用 start_server 来启动一个服务或者集成进Web框架来调用。

第三方库生态

构建stand-alone App

PyInstaller 用于将一个Python应用及其依赖打包到文件夹或可执行文件中,用户可以在不安装Python解释器以及任何模块的情况下运行打包后的应用程序。

可以使用PyInstaller来将PyWebIO应用打包成一个单独的可执行文件或文件夹:

  1. 创建pyinstaller spec (specification) 文件:

    pyi-makespec <options> app.py
    

    你需要将 app.py 替换成你PyWebIO应用的文件名。

  2. Only for PyWebIO before v1.8: Edit the spec file, change the datas parameter of Analysis:

    from pywebio.utils import pyinstaller_datas
    
    a = Analysis(
        ...
        datas=pyinstaller_datas(),
        ...
    
  3. 使用spec文件来构建可执行文件:

    pyinstaller app.spec
    

如果你希望生成一个单独的可执行文件而不是文件夹,你需要在第一步时传入 --onefile 选项。

更多PyInstaller用法请见: https://pyinstaller.readthedocs.io/en/stable/spec-files.html

数据可视化

PyWebIO支持使用第三方库进行数据可视化

Bokeh

Bokeh 是一个支持创建实时交互的数据可视化库。

在 PyWebIO 会话中调用 bokeh.io.output_notebook(notebook_type='pywebio') 来设置Bokeh输出到PyWebIO:

from bokeh.io import output_notebook
from bokeh.io import show

output_notebook(notebook_type='pywebio')
fig = figure(...)
...
show(fig)

相应demo见 bokeh demo

除了创建普通图表,Bokeh还可以通过启动Bokeh server来显示Bokeh app,Bokeh app支持向图表的添加按钮、输入框等交互组件,并向组件注册Python回调,从而创建可以与Python代码交互的图表。

在PyWebIO中,你也可以使用 bokeh.io.show() 来显示一个Bokeh App,代码示例见 bokeh_app.py

注解

Bokeh App当前仅支持默认的Tornado后端

https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/bokeh.png
pyecharts

pyecharts 是一个使用Python创建 Echarts 可视化图表的库。

在 PyWebIO 中使用 put_html() 可以输出 pyecharts 库创建的图表:

# `chart` is pyecharts chart instance
pywebio.output.put_html(chart.render_notebook())

相应demo见 pyecharts demo

https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/pyecharts.gif
plotly

plotly.py 是一个非常流行的Python数据可视化库,可以生成高质量的交互式图表。

PyWebIO 支持输出使用 plotly 库创建的图表。使用方式为在PyWebIO会话中调用:

# `fig` is plotly chart instance
html = fig.to_html(include_plotlyjs="require", full_html=False)
pywebio.output.put_html(html)

相应demo见 plotly demo

https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/plotly.png
pyg2plot

pyg2plot 是一个使用Python创建 G2Plot 可视化图表的库。

PyWebIO 支持输出使用 pyg2plot 库创建的图表。使用方式为在PyWebIO会话中调用:

# `chart` 为 pyg2plot 图表实例
pywebio.output.put_html(chart.render_notebook())

相应demo见 plotly demo

cutecharts.py

cutecharts.py 是一个可以创建具有卡通风格的可视化图表的python库。 底层使用了 chart.xkcd Javascript库。

在 PyWebIO 中使用 put_html() 可以输出 cutecharts.py 库创建的图表:

# `chart` is cutecharts chart instance
pywebio.output.put_html(chart.render_notebook())

相应demo见 cutecharts demo

https://fastly.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/cutecharts.png

Cookbook

Release notes

What’s new in PyWebIO 1.8

2023/4/10
Highlights
  • Add datatable widget (put_datatable())

  • Build reliable message transmission over HTTP-based backends (Flask and Django)

Backwards-incompatible changes
  • When use put_loading() as context manager, the output inside the context will also been removed after the context block exits.

Detailed changes
  • Add put_file_upload() pin widget.

  • Add WPA support (via config(manifest)), so PyWebIO apps can be launched like a native app on mobile devices.

  • Add type hints to all public functions (#501, thanks to 叶子)

  • Add Uzbek language support for UI labels (#539, thanks to Ulugbek)

  • Remove the NullHandler() logging handler added to pywebio logger, so the exception log from PyWebIO can be output by default.

  • Add max_payload_size param to start_server() and webio_handler() for aiohttp and fastapi backends.

  • When tdata of put_table() is list of dict, header parameter is not mandatory anymore.

  • Add pyinstaller hook, so PyWebIO apps can be packaged to executable file with pyinstaller without any extra configuration.

  • No traceback expose to user in production environment (start_server(debug=False), the default setting).

Bug fix
  • Fix memory leak after close session (#545)

v1.8.1 (2023/4/16)
  • fix (#568) global config(title) don’t work

  • fix (#569) cell_content_bar shown error

v1.8.2 (2023/4/22)
  • fix (#570) flex column config of put_datatable() don’t work

  • fix json encode error when use tuple as key in column_args of put_datatable()

What’s new in PyWebIO 1.7

2022/10/17
Highlights
  • add session reconnect to aiohttp and fastapi backends (now, all platforms support session reconnect)

Detailed changes
Bug fix
  • fix: textarea(code=True, required=True) can’t submit

  • fix: auto hold don’t work on script mode

  • fix (#389): put_select() was hidden by put_tabs()

  • fix: input_update(datalist) don’t work when datalist is not provided in input()

  • fix (#459): code textarea onchange fired when set value

  • fix (#453): put_table() error when table data is empty with rich header

  • fix load old static resource after version upgrade

  • fix cancel type raise error in single action()

  • fix (#377): error on nested onchange callback

  • fix (#468): can’t reset select()

  • fix set_env(output_animation=False) don’t work for image

What’s new in PyWebIO 1.6

2022/3/23
Detailed changes
  • use bootstrap-select to provide more user-friendly select input

  • add pin.pin.use_strict() to enable strict mode for getting pin widget value

  • Persian language support for default labels, thanks to Pikhosh

  • add color input type (#310)

  • add input check on number and float type input

Bug fix
  • fix: uncaught SessionClosedException in callback of thread-based session

  • fix(#313): slider value label don’t sync when set value

v1.6.1 (2022/5/22)
  • fix (#380): put_processbar() don’t work when name contains space

  • fix (#385): bootstrap-select issue

  • fix (#389): put_select() was hidden by put_tabs()

  • fix auto hold don’t work on script mode

  • provide a fallback way when CDN is not available

v1.6.2 (2022/7/16)
  • fix: plotly.js version error due to outdated CDN link

What’s new in PyWebIO 1.5

2021/11/20
Highlights
Detailed changes
  • enable lstrip by default in put_markdown(), and the behavior of lstrip is more clever than previous version. Deprecate strip_indent since lstrip is sufficient.

  • button disabled state support in pywebio.output.put_buttons() and pywebio.output.put_button(), and button value can be any type

  • buttons in pywebio.input.actions() support color setting

  • russian language support for frontend labels and messages. Thanks to @Priler.

  • improve default index page of pywebio.platform.path_deploy(): improve pywebio app detection and show app title.

  • compatible with latest aiohttp(v3.8)

  • enable websocket_ping_interval by default in tornado server to avoid idle connections being close in some cloud platform (like heroku)

  • exception traceback will be show in page when enable debug

  • slider input add indicator to show its current value

Bug fix
  • deep copy options and buttons parameters to avoid potential error - 81d57ba4, cb5ac8d5 - e262ea43

  • fix page width exceeding screen width (mostly on mobile devices) - 536d09e3

  • fix put_buttons() issue when buttons have same value - cb5ac8d5

  • fix layout issue when use put_markdown() - 364059ae

  • fix style issue in put_tabs() widget - f056f1ac

  • fix sibling import issue in path_deploy() - 35209a7e

  • fix “Address already in use” error when enable remote access in some cases - 8dd9877d

v1.5.1 (2021/12/21)
  • fix setitem error of pin.pin object - 3f5cf1e5

  • fix thread-based session tot closed properly - 22fbbf86..3bc7d36b>

  • fix OverflowError on 32-bit Windows - 4ac7f0e5

  • fix a sample error from cookbook - 99593db4

  • fix spawn 2 remote access processes when enable debug in flask backed - 073f8ace

v1.5.2 (2021/12/30)
  • fix #243: thread keep alive after session closed

  • fix #247: can’t use coroutine callback in put_button()

What’s new in PyWebIO 1.4

2021/10/4
Highlights
  • automatically hold session when needed

  • support for binding onclick callback on any output widget

Detailed changes
Bug fix
  • fix(#148): form can’t be submit after validation failed - e262ea43

  • fix some codemirror issues: codemirror refresh and mode auto load - b7957891, 50cc41a9

  • fix: run_js() return None when empty-value - 89ce352d

  • fix: whole output crash when a sub output fail - 31b26d09

What’s new in PyWebIO 1.3

2021/6/12
Highlights
  • New module pin to provide persistent input support.

  • Add a remote access service to start_server(). See server mode - User Guide for detail.

  • Add input_update(), add onchange callback in input functions.

  • Add support for FastAPI and Starlette.

Detailed changes
Bug fix
  • Fix table style.

  • Fix large file uploading error.

  • Fix server start error when enabled auto_open_webbrowser.

  • Fix file names overflow in file input.

  • Fix put_image() raise ‘unknown file extension’ error when use PIL Image as src.

  • Sanitize the returned filename of file_upload() to avoid interpreting as path accidentally.

  • So many other bugs fixed.

What’s new in PyWebIO 1.2

2021 3/18
Highlights
  • Websocket连接可以通过在 start_server() 中设定 reconnect_timeout 参数来支持连接重连。

  • 添加 path_deploy(), path_deploy_http()pywebio-path-deploy 命令来实现从目录中加载运行PyWebIO应用。

  • 所有的文档和示例都提供了英文版本。

  • 为一些输出相关的函数提供上下文管理器的支持,参见 output functions list

Detailed changes
  • 添加 put_info(), put_error(), put_warning(), put_success() 来显示提示消息。

  • 添加 pywebio.utils.pyinstaller_datas() 来获得使用pyinstaller打包PyWebIO应用所需要的数据文件。

  • 添加使用pyg2plot进行数据可视化的文档。

  • output()reset(), append(), insert() 方法接受任意类型作为输出内容。

  • start_server() 中添加 static_dir 参数来托管静态文件。

  • 废弃 pywebio.session.get_info() ,使用 pywebio.session.info 替代

  • 当用户使用IE浏览器时提示浏览器不被支持。

What’s new in PyWebIO 1.1

2021 2/7

距离写下PyWebIO的第一行代码过去已经整整一年了🎂 ,2020年发生了太多的事情,但对我来说又多了一份特殊的意义。新的一年继续努力💪 ,将PyWebIO做得越来越好。

Highlights
  • 添加安全性支持: put_html(), put_markdown() 中支持使用 sanitize 参数开启防 XSS 攻击

  • UI国际化支持

  • 添加SEO支持: 通过任务函数的注释或 pywebio.platform.seo() 来设置SEO信息

  • CDN支持,Web框架整合更加方便,仅需引入一条路由即可

  • 应用访问速度提升,不再使用探测请求的方式确定通信协议

Backwards-incompatible changes
Detailed changes

What’s new in PyWebIO 1.0

2021 1/17

经过快一年的开发,PyWebIO 1.0 终于完成了。与上一版本 v0.3 相比有非常多的变化:

Highlights
Backwards-incompatible changes
  • 不再使用基于锚点的输出控制模型

  • 不支持固定高度的输出区,移除 pywebio.output.set_output_fixed_height()

  • 移除 pywebio.output.set_title() , pywebio.output.set_auto_scroll_bottom(),改用 pywebio.session.set_env() 进行控制

  • 移除 pywebio.output.table_cell_buttons() ,使用 pywebio.output.put_buttons() 替代

Detailed changes by module

What’s new in PyWebIO 0.3

2020 5/13
Highlights
  • 支持输出 bokeh 数据可视化图表, 文档

  • 添加 session.get_info() 获取会话相关信息

  • 前端js代码迁移typescript

  • output.put_table() 支持跨行/列单元格, 单元格内容支持使用 put_xxx 类输出函数

Detailed changes by module
UI
  • 当与服务器连接断开时,点击前端的交互式按钮会报错提示。

pywebio.output
  • 锚点名字支持使用空格

  • 弃用 table_cell_buttons()

What’s new in PyWebIO 0.2

2020 4/30
Highlights
  • 支持与Django、aiohttp Web框架整合

  • 支持使用 plotly、pyecharts 等第三方库进行数据可视化

  • 与Web框架整合时支持同时使用基于线程和协程的会话实现

  • 添加 defer_call()hold() 会话控制函数

  • 添加 put_image() 输出图像、 remove(anchor) 移除内容

  • 加入动画提升UI体验

  • 添加测试用例,构建CI工作流

Detailed changes by module
UI
  • 添加元素显示动画

  • 页面底部添加footer

pywebio.input
  • input_group() 添加 cancelable 参数来允许用户取消输入

  • actions() 函数 button 参数支持 resetcancel 按钮类型

pywebio.output
  • 输出函数使用 anchor 参数指定输出锚点时,若锚点已经存在,则将锚点处的内容替换为当前内容。

  • clear_range() 添加添加锚点存在检查

  • scroll_to(anchor, position) 添加 position 参数精细化控制滚动位置

pywebio.platform
  • start_serverwebio_viewwebio_handle 添加跨域支持

pywebio.session
  • Session 关闭时,清理更彻底:任何还在进行的PyWebIO调用都会抛出 SessionClosedException 异常

  • fix: Session 对象构造函数无法识别 functools.partial 处理的任务函数

pywebio_battery — PyWebIO battery

Utilities that help write PyWebIO apps quickly and easily.

注解

pywebio_battery is an extension package of PyWebIO, you must install it before using it. To install this package, run pip3 install -U pywebio-battery

Functions index

服务器-客户端通信协议

PyWebIO采用服务器-客户端架构,服务端运行任务代码,通过网络与客户端(也就是用户浏览器)交互。本章介绍PyWebIO服务端与客户端通信的协议。

服务器与客户端有两种通信方式:WebSocket 和 Http 通信。

使用 Tornado或aiohttp 后端时,服务器与客户端通过 WebSocket 通信,使用 Flask或Django 后端时,服务器与客户端通过 Http 通信。

WebSocket 通信:

服务器与客户端通过WebSocket连接发送json序列化之后的PyWebIO消息

Http 通信:

  • The client polls the backend through Http GET requests, and the backend returns a list of PyWebIO messages serialized in json

  • When the user submits the form or clicks the button, the client submits data to the backend through Http POST request

为方便区分,下文将由服务器向客户端发送的数据称作command,将客户端发向服务器的数据称作event

以下介绍command和event的格式

Command

command由服务器->客户端,基本格式为:

{
    "command": ""
    "task_id": ""
    "spec": {}
}

各字段含义如下:

  • command 字段表示指令名

  • task_id 字段表示发送指令的Task id,客户端对于此命令的响应事件都会传递 task_id

  • spec 字段为指令的参数,不同指令参数不同

需要注意,以下不同命令的参数和 PyWebIO 的对应函数的参数大部分含义一致,但是也有些许不同。

以下分别对不同指令的 spec 字段进行说明:

input_group

显示一个输入表单

spec 可用字段

字段

是否必选

类型

字段说明

label

False

str

表单标题

inputs

True

list

输入项

cancelable

False

bool

表单是否可以取消
cancelable=True 则会在表单底部显示一个”取消”按钮,
用户点击取消按钮后,触发 from_cancel 事件

inputs 字段为输入项组成的列表,每一输入项为一个 dict,字段如下:

  • label: 输入标签名。必选

  • type: 输入类型。必选

  • name: 输入项id。必选

  • onchange: bool, whether to push input value when input change

  • onbulr: bool, whether to push input value when input field onblur

  • auto_focus: 自动获取输入焦点. 输入项列表中最多只能由一项的auto_focus为真

  • help_text: 帮助文字

  • 输入项HTML元素额外的HTML属性

  • Other attributes of different input types

输入类型目前有:

  • text: 文本输入

  • number: 数字输入

  • password: 密码输入

  • checkbox: 多选项

  • radio: 单选项

  • select: 下拉选择框(可单选/多选)

  • textarea: 大段文本输入

  • file: 文件上传

  • actions: Actions selection.

输入类型与html输入元素的对应关系:

Unique attributes of different input types:

  • text,number,password:

    • action: Display a button on the right of the input field. The format of action is {label: button label, callback_id: button click callback id}

  • textarea:

  • select:

    • options: {label:, value: , [selected:,] [disabled:]}

  • checkbox:

    • options: {label:, value: , [selected:,] [disabled:]}

    • inline

  • radio:

    • options: {label:, value: , [selected:,] [disabled:]}

    • inline

  • actions

    • buttons: {label:, value:, [type: 'submit'/'reset'/'cancel'], [disabled:], [color:]} .

  • file:

    • 是否允许多文件上传

    • 单个文件的最大大小(字节),超过限制将会禁止上传

    • 所有文件的最大大小(字节),超过限制将会禁止上传

  • slider

    • min_value: The minimum permitted value.

    • max_value: The maximum permitted value.

    • step: The stepping interval.

    • float: If need return a float value

update_input

更新输入项,用于对当前显示表单中输入项的 spec 进行更新

命令 spec 可用字段:

  • target_name: str The name of the target input item.

  • target_value: str, optional. Used to filter item in checkbox, radio

  • attributes: dist, fields need to be updated

    • valid_status: When it is bool, it means setting the state of the input value, pass/fail; when it is 0, it means clear the valid_status flag

    • value: Set the value of the item

    • label

    • placeholder

    • invalid_feedback

    • valid_feedback

    • help_text

    • options: only available in checkbox, radio and select type

    • other fields of item’s spec // not support the inline field

close_session

指示服务器端已经关闭连接。 spec 为空

set_session_id

将当前会话id发送至客户端,客户端可以使用此id来重连会话(仅在websocket连接中可用)。 spec 字段为会话id

destroy_form

Destroy the current form. spec of the command is empty.

表单在页面上提交之后不会自动销毁,需要使用此命令显式销毁

output

Output content

The spec fields of output commands:

  • type: content type

  • style: str, Additional css style

  • container_selector: The css selector of output widget’s content slot. If empty(default), use widget self as container

  • container_dom_id: The dom id need to be set to output widget’s content slot.

  • scope: str, 内容输出的域的css选择器。若CSS选择器匹配到页面上的多个容器,则内容会输出到每个匹配到的容器

  • int, 在输出域中输出的位置, 见 输出函数的scope相关参数

  • click_callback_id:

  • 不同type时的特有字段

container_selector and container_dom_id is used to implement output context manager.

type 的可选值及特有字段:

  • type: markdown

    • content: str

    • options: dict, marked.js options

    • sanitize: bool, 是否使用 DOMPurify 对内容进行过滤来防止XSS攻击。

  • type: html

    • content: str

    • sanitize: bool, 是否使用 DOMPurify 对内容进行过滤来防止XSS攻击。

  • type: text

    • content: str

    • inline: bool, Use text as an inline element (no line break at the end of the text)

  • type: buttons

    • callback_id:

    • buttons:[ {value:, label:, [color:], [disabled:]},…]

    • small: bool,是否显示为小按钮样式

    • group: bool, Whether to group the buttons together

    • link: bool,是否显示为链接样式

    • outline: bool, Whether enable outline style.

  • type: file

    • name: 下载保存为的文件名

    • content: 文件base64编码的内容

  • type: table

    • data: Table data, which is a two-dimensional list, the first row is table header.

    • span: cell span info. Format: {“[row id],[col id]”: {“row”:row span, “col”:col span }}

  • type: pin

    • input: input spec, same as the item of input_group.inputs

  • type: scope

    • dom_id: the DOM id need to be set to this widget

    • contents list: list of output spec

  • type: scrollable

    • contents:

    • min_height:

    • max_height:

    • keep_bottom:

    • border:

  • type: tabs

    • tabs:

  • type: custom_widget

    • template:

    • data:

pin_value

命令 spec 可用字段:

  • name

pin_update

命令 spec 可用字段:

  • name

  • attributes: dist, fields need to be updated

pin_wait

命令 spec 可用字段:

  • names: list,

  • timeout: int,

pin_onchange

set a callback which is invoked when the value of pin widget is changed

The spec fields of pin_onchange commands:

  • name: string

  • callback_id: string, if None, not set callback

  • clear: bool

toast

Show a notification message

The spec fields of popup commands:

  • content

  • duration

  • position: 'left' / 'center' / 'right'

  • color: hexadecimal color value starting with ‘#’

  • callback_id

close_popup

Close the current popup window.

spec of the command is empty.

set_env

Config the environment of current session.

The spec fields of set_env commands:

  • title (str)

  • output_animation (bool)

  • auto_scroll_bottom (bool)

  • http_pull_interval (int)

  • input_panel_fixed (bool)

  • input_panel_min_height (int)

  • input_panel_init_height (int)

  • input_auto_focus (bool)

output_ctl

Output control

The spec fields of output_ctl commands:

  • set_scope: scope name

    • container: 新创建的scope的父scope的css选择器

    • position: int, 在父scope中创建此scope的位置.

    • scope已经存在时如何操作:

      • null/不指定: 表示立即返回不进行任何操作

      • ’remove’ : 先移除旧scope再创建新scope

      • ’clear’ : 将旧scope的内容清除,不创建新scope

      • 'blank': Clear the contents of the old scope and keep the height, don’t create a new scope

  • loose: css selector of the scope, set the scope not to keep the height (i.e., revoke the effect of set_scope(if_exist='blank'))

  • clear: 需要清空的scope的css选择器

  • clear_before

  • clear_after

  • clear_range:[,]

  • scroll_to
    • position: top/middle/bottom 与scroll_to一起出现, 表示滚动页面,让scope位于屏幕可视区域顶部/中部/底部

  • remove: 将给定的scope连同scope处的内容移除

run_script

run javascript code in user’s browser

The spec fields of run_script commands:

  • code: 字符串格式的要运行的js代码

  • args: 传递给代码的局部变量。字典类型,字典键表示变量名,字典值表示变量值(变量值需要可以被json序列化)

  • eval: bool, whether to submit the return value of javascript code

download

Send file to user

The spec fields of download commands:

  • name: str, File name when downloading

  • content: str, File content in base64 encoding.

Event

Event消息由客户端发往服务端。基本格式:

{
    event: event name
    task_id: ""
    data: object/str
}

event 表示事件名称。 data 为事件所携带的数据,其根据事件不同内容也会不同,不同事件对应的 data 字段如下:

input_event

表单发生更改时触发

  • event_name: 目前可用值 ’blur’,表示输入项失去焦点

  • name: 输入项name

  • value: 输入项值

注意: checkbox radio 不产生blur事件

callback

用户点击显示区的按钮时触发

callback 事件中,task_id 为对应的 button 组件的 callback_id 字段; 事件的 data 为被点击button的 value

from_submit

用户提交表单时触发

事件 data 字段为表单 name -> 表单值 的字典

from_cancel

表单取消输入

The data of the event is None

js_yield

submit data from js. It’s a common event to submit data to backend.

事件 data 字段为相应的数据

Indices and tables

Discussion and support