123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815 |
- User's guide
- ============
- If you are familiar with web development, you may not be accustomed to the usage of PyWebIO described below, which is
- different from the traditional web development pattern that backend implement api and frontend display content.
- In PyWebIO, you only need to write code in Python.
- In fact, the way of writing PyWebIO applications is more like writing a console program, except that the terminal here
- becomes a browser. Using the imperative API provided by PyWebIO, you can simply call ``put_text()``, ``put_image()``,
- ``put_table()`` and other functions to output text, pictures, tables and other content to the browser, or you can call
- some functions such as ``input()``, ``select()``, ``file_upload()`` to display different forms on the browser to get
- user input. In addition, PyWebIO also provides support for click events, layout, etc. PyWebIO aims to allow you to use
- the least code to interact with the user and provide a good user experience as much as possible.
- 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 <https://play.pywebio.online/>`_ is a good place to write, run and share your PyWebIO code online.
- Input
- ------------
- The input functions are defined in the :doc:`pywebio.input </input>` module and can be imported using ``from pywebio.input import *``.
- When calling the input function, an input form will be popped up on the browser. PyWebIO's input functions is blocking
- (same as Python's built-in ``input()`` function) and will not return until the form is successfully submitted.
- Basic input
- ^^^^^^^^^^^^^
- Here are some basic types of input.
- Text input:
- .. exportable-codeblock::
- :name: text-input
- :summary: Text input
- age = input("How old are you?", type=NUMBER)
- put_text('age = %r' % age) # ..demo-only
- After running the above code, the browser will pop up a text input field to get the input. After the user completes the
- input and submits the form, the function returns the value entered by the user.
- Here are some other types of input functions:
- .. exportable-codeblock::
- :name: basic-input
- :summary: Basic input
- # Password input
- password = input("Input password", type=PASSWORD)
- put_text('password = %r' % password) # ..demo-only
- ## ----
- # Drop-down selection
- gift = select('Which gift you want?', ['keyboard', 'ipad'])
- put_text('gift = %r' % gift) # ..demo-only
- ## ----
- # Checkbox
- agree = checkbox("User Term", options=['I agree to terms and conditions'])
- put_text('agree = %r' % agree) # ..demo-only
- ## ----
- # Single choice
- answer = radio("Choose one", options=['A', 'B', 'C', 'D'])
- put_text('answer = %r' % answer) # ..demo-only
- ## ----
- # Multi-line text input
- text = textarea('Text Area', rows=3, placeholder='Some text')
- put_text('text = %r' % text) # ..demo-only
- ## ----
- # File Upload
- img = file_upload("Select a image:", accept="image/*")
- if img: # ..demo-only
- put_image(img['content'], title=img['filename']) # ..demo-only
- Parameter of input functions
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- There are many parameters that can be passed to the input function(for complete parameters, please refer to the
- :doc:`function document </input>`):
- .. exportable-codeblock::
- :name: input-args
- :summary: Parameter of input functions
- input('This is label', type=TEXT, placeholder='This is placeholder',
- help_text='This is help text', required=True)
- The results of the above example are as follows:
- .. image:: /assets/input_1.png
- You can specify a validation function for the input by using ``validate`` parameter. The validation function should
- return ``None`` when the check passes, otherwise an error message will be returned:
- .. exportable-codeblock::
- :name: input-valid-func
- :summary: Input validate function for
- 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)
- put_text('age = %r' % age) # ..demo-only
- When the user input an illegal value, the input field is displayed as follows:
- .. image:: /assets/input_2.png
- You can use ``code`` parameter in :func:`pywebio.input.textarea()` to make a code editing textarea.
- .. exportable-codeblock::
- :name: codemirror
- :summary: Code editing by using textarea
- code = textarea('Code Edit', code={
- 'mode': "python",
- 'theme': 'darcula',
- }, value='import something\n# Write your python code')
- put_code(code, language='python') # ..demo-only
- The results of the above example are as follows:
- .. image:: /assets/codemirror_textarea.png
- Input Group
- ^^^^^^^^^^^^^
- PyWebIO uses input group to get multiple inputs in a single form. `pywebio.input.input_group()` accepts a list of
- single input function call as parameter, and returns a dictionary with the ``name`` of the single input as its key
- and the input data as its value:
- .. exportable-codeblock::
- :name: input-group
- :summary: Input Group
- def check_age(p): # ..demo-only
- if p < 10: # ..demo-only
- return 'Too young!!' # ..demo-only
- if p > 60: # ..demo-only
- return 'Too old!!' # ..demo-only
- # ..demo-only
- 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'])
- The input group also supports using ``validate`` parameter to set the validation function, which accepts the entire form data as parameter:
- .. exportable-codeblock::
- :name: input-group-validate
- :summary: Input Group validation
- def check_age(p): # single input item validation # ..demo-only
- if p < 10: # ..demo-only
- return 'Too young!!' # ..demo-only
- if p > 60: # ..demo-only
- return 'Too old!!' # ..demo-only
- # ..demo-only
- 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!')
- data = input_group("Basic info",[ # ..demo-only
- input('Input your name', name='name'), # ..demo-only
- input('Input your age', name='age', type=NUMBER, validate=check_age) # ..demo-only
- ], validate=check_form) # ..demo-only
- put_text(data['name'], data['age']) # ..demo-only
- .. attention::
- PyWebIO determines whether the input function is in `input_group()` or is called alone according to whether the
- ``name`` parameter is passed. So when calling an input function alone, **do not** set the ``name`` parameter;
- when calling the input function in `input_group()`, you **must** provide the ``name`` parameter.
- Output
- ------------
- The output functions are all defined in the :doc:`pywebio.output </output>` module and can be imported using
- ``from pywebio.output import *``.
- When output functions is called, the content will be output to the browser in real time. The output functions
- can be called at any time during the application lifetime.
- Basic Output
- ^^^^^^^^^^^^^^
- Using output functions, you can output a variety of content, such as text, tables, images and so on:
- .. exportable-codeblock::
- :name: basic-output
- :summary: Basic Output
- # 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 # ..doc-only
- put_image('http://example.com/some-image.png') # internet image # ..doc-only
- put_image('https://www.python.org/static/img/python-logo.png') # ..demo-only
- ## ----
- # 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 ๐')
- For all output functions provided by PyWebIO, please refer to the :doc:`pywebio.output </output>` module.
- In addition, PyWebIO also supports data visualization with some third-party libraries,
- see :doc:`Third-party library ecology </libraries_support>`.
- .. note::
- If you use PyWebIO in interactive execution environment of Python shell, IPython or jupyter notebook,
- you need call `show()` method explicitly to show output::
- >>> put_text("Hello world!").show()
- >>> put_table([
- ... ['A', 'B'],
- ... [put_markdown(...), put_text('C')]
- ... ]).show()
- .. _combine_output:
- Combined Output
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- The output functions whose name starts with ``put_`` can be combined with some output functions as part of the final output:
- You can pass ``put_xxx()`` calls to `put_table() <pywebio.output.put_table>` as cell content:
- .. exportable-codeblock::
- :name: putxxx
- :summary: Combination output
- 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=...)], # ..doc-only
- ['buttons', put_buttons(['A', 'B'], onclick=put_text)], # ..demo-only
- ['markdown', put_markdown('`Awesome PyWebIO!`')],
- ['file', put_file('hello.text', b'hello world')],
- ['table', put_table([['A', 'B'], ['C', 'D']])]
- ])
- The results of the above example are as follows:
- .. image:: /assets/put_table.png
- Similarly, you can pass ``put_xxx()`` calls to `popup() <pywebio.output.popup>` as the popup content:
- .. exportable-codeblock::
- :name: popup
- :summary: Popup
- 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)
- ])
- In addition, you can use `put_widget() <pywebio.output.put_widget>` to make your own output widgets that can accept ``put_xxx()`` calls.
- For a full list of functions that accept ``put_xxx()`` calls as content, see :ref:`Output functions list <output_func_list>`
- **Context Manager**
- Some output functions that accept ``put_xxx()`` calls as content can be used as context manager:
- .. exportable-codeblock::
- :name: output-context-manager
- :summary: Output as context manager
- with put_collapse('This is title'):
- for i in range(4):
- put_text(i)
- put_table([
- ['Commodity', 'Price'],
- ['Apple', '5.5'],
- ['Banana', '7'],
- ])
- For a full list of functions that support context manager, see :ref:`Output functions list <output_func_list>`
- .. _callback:
- Click Callback
- ^^^^^^^^^^^^^^^^
- As we can see from the above, the interaction of PyWebIO has two parts: input and output. The input function of PyWebIO
- is blocking, a form will be displayed on the user's web browser when calling input function, the input function will
- not return until the user submits the form. The output function is used to output content to the browser in real time.
- The input and output behavior of PyWebIO is consistent with the console program. That's why we say PyWebIO turning the
- browser into a "rich text terminal". So you can write PyWebIO applications in script programming way.
- In addition, PyWebIO also supports event callbacks: PyWebIO allows you to output some buttons and bind callbacks to them.
- The provided callback function will be executed when the button is clicked.
- This is an example:
- .. exportable-codeblock::
- :name: onclick-callback
- :summary: Event callback
- 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))],
- ])
- The call to `put_table() <pywebio.output.put_table>` will not block. When user clicks a button, the corresponding
- callback function will be invoked:
- .. image:: /assets/table_onclick.*
- Of course, PyWebIO also supports outputting individual button:
- .. exportable-codeblock::
- :name: put-buttons
- :summary: Event callback of button widget
- 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
- In fact, all output can be bound to click events, not just buttons. You can call ``onclick()`` method after the output
- function (function name like ``put_xxx()``) call:
- .. exportable-codeblock::
- :name: onclick
- :summary: Click callback on any output
- put_image('some-image.png').onclick(lambda: toast('You click an image')) # ..doc-only
- put_image('https://www.python.org/static/img/python-logo.png').onclick(lambda: toast('You click an image')) # ..demo-only
- # set onclick in combined output
- put_table([
- ['Commodity', 'Price'],
- ['Apple', put_text('5.5').onclick(lambda: toast('You click the text'))],
- ])
- The return value of ``onclick()`` method is the object itself so it can be used in combined output.
- .. _output_scope:
- Output Scope
- ^^^^^^^^^^^^^^
- PyWebIO uses the scope model to give more control to the location of content output. The output scope is a container
- of output content. You can create a scope in somewhere and append content to it.
- Each output function (function name like ``put_xxx()``) will output its content to a scope, the default is "current scope".
- The "current scope" is set by `use_scope() <pywebio.output.use_scope>`.
- .. _use_scope:
- **use_scope()**
- You can use `use_scope() <pywebio.output.use_scope>` to open and enter a new output scope, or enter an existing output scope:
- .. exportable-codeblock::
- :name: use-scope
- :summary: use `use_scope()` to open or enter scope
- with use_scope('scope1'): # open and enter a new output: 'scope1'
- put_text('text1 in scope1') # output text to scope1
- put_text('text in parent scope of scope1') # output text to ROOT scope
- with use_scope('scope1'): # enter an existing scope: 'scope1'
- put_text('text2 in scope1') # output text to scope1
- The results of the above code are as follows::
- text1 in scope1
- text2 in scope1
- text in parent scope of scope1
- You can use ``clear`` parameter in `use_scope() <pywebio.output.use_scope>` to clear the existing content before entering the scope:
- .. exportable-codeblock::
- :name: use-scope-clear
- :summary: `use_scope()`'s `clear` parameter
- 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')
- The results of the above code are as follows::
- text in scope2
- text in parent scope of scope2
- `use_scope() <pywebio.output.use_scope>` can also be used as decorator:
- .. exportable-codeblock::
- :name: use-scope-decorator
- :summary: `use_scope()` as decorator
- import time # ..demo-only
- from datetime import datetime
- @use_scope('time', clear=True)
- def show_time():
- put_text(datetime.now())
- while 1: # ..demo-only
- show_time() # ..demo-only
- time.sleep(1) # ..demo-only
- When calling ``show_time()`` for the first time, a ``time`` scope will be created, and the current time will be output
- to it. And then every time the ``show_time()`` is called, the new content will replace the previous content.
- Scopes can be nested. At the beginning, PyWebIO applications have only one ``ROOT`` scope.
- You can create new scope in a scope. For example, the following code will create 3 scopes:
- .. exportable-codeblock::
- :name: use-scope-nested
- :summary: Nested 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')
- put_html("""<style> # ..demo-only
- #pywebio-scope-A {border: 1px solid red;} # ..demo-only
- #pywebio-scope-B {border: 1px solid blue;margin:2px} # ..demo-only
- #pywebio-scope-C {border: 1px solid green;margin-top:2px} # ..demo-only
- </style>""") # ..demo-only
- put_text() # ..demo-only
- put_buttons([('Put text to %s' % i, i) for i in ('A', 'B', 'C')], lambda s: put_text(s, scope=s)) # ..demo-only
- The above code will generate the following scope layout::
- โโROOTโโโโโโโโโโโโโโโโโโโโโ
- โ โ
- โ โโAโโโโโโโโโโโโโโโโโโโโ โ
- โ โ Text in scope A โ โ
- โ โ โโBโโโโโโโโโโโโโโโโ โ โ
- โ โ โ Text in scope B โ โ โ
- โ โ โโโโโโโโโโโโโโโโโโโ โ โ
- โ โโโโโโโโโโโโโโโโโโโโโโโ โ
- โ โ
- โ โโCโโโโโโโโโโโโโโโโโโโโ โ
- โ โ Text in scope C โ โ
- โ โโโโโโโโโโโโโโโโโโโโโโโ โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโ
- .. _put_scope:
- **put_scope()**
- We already know that the scope is a container of output content. So can we use this container as a sub-item
- of a output (like, set a cell in table as a container)? Yes, you can use `put_scope() <pywebio.output.put_scope>` to
- create a scope explicitly.
- The function name starts with ``put_``, which means it can be pass to the functions that accept ``put_xxx()`` calls.
- .. exportable-codeblock::
- :name: put_scope
- :summary: `put_scope()`
- 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)
- .. caution:: It is not allowed to have two scopes with the same name in the application.
- **Scope control**
- In addition to `use_scope() <pywebio.output.use_scope>` and `put_scope() <pywebio.output.put_scope>`,
- PyWebIO also provides the following scope control functions:
- * `clear(scope) <pywebio.output.clear>` : Clear the contents of the scope
- * `remove(scope) <pywebio.output.remove>` : Remove scope
- * `scroll_to(scope) <pywebio.output.scroll_to>` : Scroll the page to the scope
- Also, all output functions (function name like ``put_xxx()``) support a ``scope`` parameter to specify the destination
- scope to output, and support a ``position`` parameter to specify the insert position in target scope.
- Refer :ref:`output module <scope_param>` for more information.
- Layout
- ^^^^^^^^^^^^^^
- In general, using the output functions introduced above is enough to output what you want, but these outputs are arranged
- vertically. If you want to create a more complex layout (such as displaying a code block on the left side of the page
- and an image on the right), you need to use layout functions.
- The ``pywebio.output`` module provides 3 layout functions, and you can create complex layouts by combining them:
- * `put_row() <pywebio.output.put_row>` : Use row layout to output content. The content is arranged horizontally
- * `put_column() <pywebio.output.put_column>` : Use column layout to output content. The content is arranged vertically
- * `put_grid() <pywebio.output.put_grid>` : Output content using grid layout
- Here is an example by combining ``put_row()`` and ``put_column()``:
- .. exportable-codeblock::
- :name: put-row-column
- :summary: Layout functions
- 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')
- ])
- The results of the above example are as follows:
- .. image:: /assets/layout.png
- :align: center
- The layout function also supports customizing the size of each part::
- put_row([put_image(...), put_image(...)], size='40% 60%') # The ratio of the width of two images is 2:3
- For more information, please refer to the :ref:`layout functions documentation <style_and_layout>`.
- .. _style:
- Style
- ^^^^^^^^^^^^^^
- If you are familiar with `CSS <https://en.wikipedia.org/wiki/CSS>`_ styles,
- you can use the ``style()`` method of output return to set a custom style for the output.
- You can set the CSS style for a single ``put_xxx()`` output:
- .. exportable-codeblock::
- :name: style-demo
- :summary: style of output
- 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')
- The return value of ``style()`` method is the object itself so it can be used in combined output.
- .. _server_and_script_mode:
- Run application
- ----------------
- In PyWebIO, there are two modes to run PyWebIO applications: running as a script and using
- `pywebio.start_server() <pywebio.platform.tornado.start_server>` or
- `pywebio.platform.path_deploy() <pywebio.platform.path_deploy>` to run as a web service.
- Overview
- ^^^^^^^^^^^^^^
- .. _server_mode:
- **Server mode**
- In server mode, PyWebIO will start a web server to continuously provide services. When the user accesses the service
- address, PyWebIO will open a new session and run PyWebIO application in it.
- `start_server() <pywebio.platform.tornado.start_server>` is the most common way to start a web server to serve given
- PyWebIO applications::
- 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)
- Now head over to http://127.0.0.1:8080/, and you should see your hello greeting.
- By using ``debug=True`` to enable debug mode, the server will automatically reload if code changes.
- The `start_server() <pywebio.platform.tornado.start_server>` provide a remote access support, when enabled
- (by passing `remote_access=True` to `start_server()`), you will get a public, shareable address for the current
- application, others can access your application in their browser via this address. Because the processing happens
- on your device (as long as your device stays on!), you don't have to worry about any dependencies.
- Using remote access makes it easy to temporarily share the application with others.
- Another way to deploy PyWebIO application as web service is using `path_deploy() <pywebio.platform.path_deploy>`.
- `path_deploy() <pywebio.platform.path_deploy>` is used to deploy the PyWebIO applications from a directory.
- Just define PyWebIO applications in python files under this directory, and you can access them via the path in the URL.
- Refer to :ref:`platform module <dir_deploy>` for more information.
- .. attention::
- Note that in Server mode, all functions from ``pywebio.input``, ``pywebio.output`` and ``pywebio.session`` modules can only be called in
- the context of PyWebIO application functions. For example, the following code is **not allowed**::
- import pywebio
- from pywebio.input import input
- port = input('Input port number:') # โ error
- pywebio.start_server(my_task_func, port=int(port))
- **Script mode**
- If you never call ``start_server()`` or ``path_deploy()`` in your code, then you are running PyWebIO application as script mode.
- In script mode, a web browser page will be open automatically when running to the first call to PyWebIO interactive functions,
- and all subsequent PyWebIO interactions will take place on this page. When the script exit, the page will be inactive.
- If the user closes the browser before the script exiting, then subsequent calls to PyWebIO's interactive functions
- will cause a `SessionException <pywebio.exceptions.SessionException>` exception.
- .. _thread_in_server_mode:
- Concurrent
- ^^^^^^^^^^^^^^
- PyWebIO can be used in a multi-threading environment.
- **Script mode**
- In script mode, you can freely start new thread and call PyWebIO interactive functions in it.
- When all `non-daemonic <https://docs.python.org/3/library/threading.html#thread-objects>`_ threads finish running, the script exits.
- **Server mode**
- In server mode, if you need to use PyWebIO interactive functions in new thread, you need to use
- `pywebio.session.register_thread(thread) <pywebio.session.register_thread>` to register the new thread
- (so that PyWebIO can know which session the thread belongs to). If the PyWebIO interactive function is not used in
- the new thread, no registration is required. Threads that are not registered with
- `register_thread(thread) <pywebio.session.register_thread>` calling PyWebIO's interactive functions will cause
- `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>`.
- Example of using multi-threading in Server mode::
- 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)
- .. _session_close:
- Close of session
- ^^^^^^^^^^^^^^^^^
- When user close the browser page, the session will be closed. After the browser page is closed, PyWebIO input function
- calls that have not yet returned in the current session will cause `SessionClosedException <pywebio.exceptions.SessionClosedException>`,
- and subsequent calls to PyWebIO interactive functions will cause `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>`
- or `SessionClosedException <pywebio.exceptions.SessionClosedException>`.
- In most cases, you don't need to catch those exceptions, because let those exceptions to abort the running is the right way to exit.
- You can use `pywebio.session.defer_call(func) <pywebio.session.defer_call>` to set the function to be called when the
- session closes. `defer_call(func) <pywebio.session.defer_call>` can be used for resource cleaning. You can call
- `defer_call(func) <pywebio.session.defer_call>` multiple times in the session, and the set functions will be executed
- sequentially after the session closes.
- More about PyWebIO
- ---------------------
- By now, you already get the most important features of PyWebIO and can start to write awesome PyWebIO applications.
- However, there are some other useful features we don't cover in the above. Here we just make a briefly explain about them.
- When you need them in your application, you can refer to their document.
- Also, :doc:`here </cookbook>` is a cookbook where you can find some useful code snippets for your PyWebIO application.
- ``session`` module
- ^^^^^^^^^^^^^^^^^^^^
- The :doc:`pywebio.session </session>` module give you more control to session.
- * Use `set_env() <pywebio.session.set_env>` to configure the title, page appearance, input panel and so on for current session.
- * The `info <pywebio.session.info>` object provides a lot information about the current session,
- such as the user IP address, user language and user browser information.
- * `local <pywebio.session.local>` is a session-local storage, it used to save data whose values are session specific.
- * `run_js() <pywebio.session.run_js>` let you execute JavaScript code in user's browser,
- and `eval_js() <pywebio.session.eval_js>` let you execute JavaScript expression and get the value of it.
- ``pin`` module
- ^^^^^^^^^^^^^^^^^^^^
- As you already know, the input function of PyWebIO is blocking and the input form will be destroyed after successful submission.
- In some cases, you may want to make the input form not disappear after submission, and can continue to receive input.
- So PyWebIO provides the :doc:`pywebio.pin </pin>` module to achieve persistent input by pinning input widgets to the page.
- ``platform`` module
- ^^^^^^^^^^^^^^^^^^^^
- The :doc:`pywebio.platform </platform>` module provides support for deploying PyWebIO applications in different ways.
- There are two protocols (WebSocket and HTTP) can be used in server to communicates with the browser. The WebSocket is
- used by default. If you want to use HTTP protocol, you can choose other ``start_server()`` functions in this module.
- You might want to set some web page related configuration (such as SEO information, js and css injection) for your PyWebIO application,
- `pywebio.config() <pywebio.config>` can be helpful.
- Advanced features
- ^^^^^^^^^^^^^^^^^^^^
- The PyWebIO application can be integrated into an existing Python web project, the PyWebIO application and the web
- project share a web framework. Refer to :ref:`Advanced Topic: Integration with Web Framework <integration_web_framework>`
- for more information.
- PyWebIO also provides support for coroutine-based sessions. Refer to :ref:`Advanced Topic: Coroutine-based session <coroutine_based_session>`
- for more information.
- If you try to bundles your PyWebIO application into a stand-alone executable file, to make users can run the application
- without installing a Python interpreter or any modules, you might want to refer to :ref:`Libraries support: Build stand-alone App <stand_alone_app>`
- If you want to make some data visualization in your PyWebIO application, you can't miss :ref:`Libraries support: Data visualization <visualization>`
- Last but not least
- ---------------------
- This is basically all features of PyWebIO, you can continue to read the rest of the documents, or start writing your PyWebIO applications now.
- Finally, please allow me to provide one more suggestion. When you encounter a design problem when using PyWebIO, you can
- ask yourself a question: What would I do if it is in a terminal program?
- If you already have the answer, it can be done in the same way with PyWebIO. If the problem persists or the solution is
- not good enough, you can consider the :ref:`callback mechanism <callback>` or :doc:`pin <./pin>` module.
- OK, Have fun with PyWebIO!
|