guide.rst 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. User's guide
  2. ============
  3. If you are familiar with web development, you may not be accustomed to the usage of PyWebIO described below, which is
  4. different from the traditional web development pattern that backend implement api and frontend display content.
  5. In PyWebIO, you only need to write code in Python.
  6. In fact, the way of writing PyWebIO applications is more like writing a console program, except that the terminal here
  7. becomes a browser. Using the imperative API provided by PyWebIO, you can simply call ``put_text()``, ``put_image()``,
  8. ``put_table()`` and other functions to output text, pictures, tables and other content to the browser, or you can call
  9. some functions such as ``input()``, ``select()``, ``file_upload()`` to display different forms on the browser to get
  10. user input. In addition, PyWebIO also provides support for click events, layout, etc. PyWebIO aims to allow you to use
  11. the least code to interact with the user and provide a good user experience as much as possible.
  12. This user guide introduces you the most of the features of PyWebIO. There is a demo link at the top right of the example
  13. codes in this document, where you can run the example code online and see what happens.
  14. Input
  15. ------------
  16. The input functions are defined in the :doc:`pywebio.input </input>` module and can be imported using ``from pywebio.input import *``.
  17. When calling the input function, an input form will be popped up on the browser. PyWebIO's input functions is blocking
  18. (same as Python's built-in ``input()`` function) and will not return until the form is successfully submitted.
  19. Basic input
  20. ^^^^^^^^^^^^^
  21. Here are some basic types of input.
  22. Text input:
  23. .. exportable-codeblock::
  24. :name: text-input
  25. :summary: Text input
  26. age = input("How old are you?", type=NUMBER)
  27. put_text('age = %r' % age) # ..demo-only
  28. After running the above code, the browser will pop up a text input field to get the input. After the user completes the
  29. input and submits the form, the function returns the value entered by the user.
  30. Here are some other types of input functions:
  31. .. exportable-codeblock::
  32. :name: basic-input
  33. :summary: Basic input
  34. # Password input
  35. password = input("Input password", type=PASSWORD)
  36. put_text('password = %r' % password) # ..demo-only
  37. ## ----
  38. # Drop-down selection
  39. gift = select('Which gift you want?', ['keyboard', 'ipad'])
  40. put_text('gift = %r' % gift) # ..demo-only
  41. ## ----
  42. # Checkbox
  43. agree = checkbox("User Term", options=['I agree to terms and conditions'])
  44. put_text('agree = %r' % agree) # ..demo-only
  45. ## ----
  46. # Single choice
  47. answer = radio("Choose one", options=['A', 'B', 'C', 'D'])
  48. put_text('answer = %r' % answer) # ..demo-only
  49. ## ----
  50. # Multi-line text input
  51. text = textarea('Text Area', rows=3, placeholder='Some text')
  52. put_text('text = %r' % text) # ..demo-only
  53. ## ----
  54. # File Upload
  55. img = file_upload("Select a image:", accept="image/*")
  56. if img: # ..demo-only
  57. put_image(img['content'], title=img['filename']) # ..demo-only
  58. Parameter of input functions
  59. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  60. There are many parameters that can be passed to the input function(for complete parameters, please refer to the
  61. :doc:`function document </input>`):
  62. .. exportable-codeblock::
  63. :name: input-args
  64. :summary: Parameter of input functions
  65. input('This is label', type=TEXT, placeholder='This is placeholder',
  66. help_text='This is help text', required=True)
  67. The results of the above example are as follows:
  68. .. image:: /assets/input_1.png
  69. You can specify a validation function for the input by using ``validate`` parameter. The validation function should
  70. return ``None`` when the check passes, otherwise an error message will be returned:
  71. .. exportable-codeblock::
  72. :name: input-valid-func
  73. :summary: Input validate function for
  74. def check_age(p): # return None when the check passes, otherwise return the error message
  75. if p < 10:
  76. return 'Too young!!'
  77. if p > 60:
  78. return 'Too old!!'
  79. age = input("How old are you?", type=NUMBER, validate=check_age)
  80. put_text('age = %r' % age) # ..demo-only
  81. When the user input an illegal value, the input field is displayed as follows:
  82. .. image:: /assets/input_2.png
  83. You can use ``code`` parameter in :func:`pywebio.input.textarea()` to make a code editing textarea.
  84. .. exportable-codeblock::
  85. :name: codemirror
  86. :summary: Code editing by using textarea
  87. code = textarea('Code Edit', code={
  88. 'mode': "python",
  89. 'theme': 'darcula',
  90. }, value='import something\n# Write your python code')
  91. put_code(code, language='python') # ..demo-only
  92. The results of the above example are as follows:
  93. .. image:: /assets/codemirror_textarea.png
  94. Input Group
  95. ^^^^^^^^^^^^^
  96. PyWebIO uses input group to get multiple inputs in a single form. `pywebio.input.input_group()` accepts a list of
  97. single input function call as parameter, and returns a dictionary with the ``name`` of the single input as its key
  98. and the input data as its value:
  99. .. exportable-codeblock::
  100. :name: input-group
  101. :summary: Input Group
  102. def check_age(p): # ..demo-only
  103. if p < 10: # ..demo-only
  104. return 'Too young!!' # ..demo-only
  105. if p > 60: # ..demo-only
  106. return 'Too old!!' # ..demo-only
  107. # ..demo-only
  108. data = input_group("Basic info",[
  109. input('Input your name', name='name'),
  110. input('Input your age', name='age', type=NUMBER, validate=check_age)
  111. ])
  112. put_text(data['name'], data['age'])
  113. The input group also supports using ``validate`` parameter to set the validation function, which accepts the entire form data as parameter:
  114. .. exportable-codeblock::
  115. :name: input-group-validate
  116. :summary: Input Group validation
  117. def check_age(p): # single input item validation # ..demo-only
  118. if p < 10: # ..demo-only
  119. return 'Too young!!' # ..demo-only
  120. if p > 60: # ..demo-only
  121. return 'Too old!!' # ..demo-only
  122. # ..demo-only
  123. def check_form(data): # return (input name, error msg) when validation fail
  124. if len(data['name']) > 6:
  125. return ('name', 'Name too long!')
  126. if data['age'] <= 0:
  127. return ('age', 'Age can not be negative!')
  128. data = input_group("Basic info",[ # ..demo-only
  129. input('Input your name', name='name'), # ..demo-only
  130. input('Input your age', name='age', type=NUMBER, validate=check_age) # ..demo-only
  131. ], validate=check_form) # ..demo-only
  132. put_text(data['name'], data['age']) # ..demo-only
  133. .. attention::
  134. PyWebIO determines whether the input function is in `input_group()` or is called alone according to whether the
  135. ``name`` parameter is passed. So when calling an input function alone, **do not** set the ``name`` parameter;
  136. when calling the input function in `input_group()`, you **must** provide the ``name`` parameter.
  137. Output
  138. ------------
  139. The output functions are all defined in the :doc:`pywebio.output </output>` module and can be imported using
  140. ``from pywebio.output import *``.
  141. When output functions is called, the content will be output to the browser in real time. The output functions
  142. can be called at any time during the application lifetime.
  143. Basic Output
  144. ^^^^^^^^^^^^^^
  145. Using output functions, you can output a variety of content, such as text, tables, images and so on:
  146. .. exportable-codeblock::
  147. :name: basic-output
  148. :summary: Basic Output
  149. # Text Output
  150. put_text("Hello world!")
  151. ## ----
  152. # Table Output
  153. put_table([
  154. ['Commodity', 'Price'],
  155. ['Apple', '5.5'],
  156. ['Banana', '7'],
  157. ])
  158. ## ----
  159. # Image Output
  160. put_image(open('/path/to/some/image.png', 'rb').read()) # local image # ..doc-only
  161. put_image('http://example.com/some-image.png') # internet image # ..doc-only
  162. put_image('https://www.python.org/static/img/python-logo.png') # ..demo-only
  163. ## ----
  164. # Markdown Output
  165. put_markdown('~~Strikethrough~~')
  166. ## ----
  167. # File Output
  168. put_file('hello_word.txt', b'hello word!')
  169. ## ----
  170. # Show a PopUp
  171. popup('popup title', 'popup text content')
  172. # Show a notification message
  173. toast('New message ๐Ÿ””')
  174. For all output functions provided by PyWebIO, please refer to the :doc:`pywebio.output </output>` module.
  175. In addition, PyWebIO also supports data visualization with some third-party libraries,
  176. see :doc:`Third-party library ecology </libraries_support>`.
  177. .. note::
  178. If you use PyWebIO in interactive execution environment of Python shell, IPython or jupyter notebook,
  179. you need call `show()` method explicitly to show output::
  180. >>> put_text("Hello world!").show()
  181. >>> put_table([
  182. ... ['A', 'B'],
  183. ... [put_markdown(...), put_text('C')]
  184. ... ]).show()
  185. .. _combine_output:
  186. Combined Output
  187. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  188. The output functions whose name starts with ``put_`` can be combined with some output functions as part of the final output:
  189. You can pass ``put_xxx()`` calls to `put_table() <pywebio.output.put_table>` as cell content:
  190. .. exportable-codeblock::
  191. :name: putxxx
  192. :summary: Combination output
  193. put_table([
  194. ['Type', 'Content'],
  195. ['html', put_html('X<sup>2</sup>')],
  196. ['text', '<hr/>'], # equal to ['text', put_text('<hr/>')]
  197. ['buttons', put_buttons(['A', 'B'], onclick=...)], # ..doc-only
  198. ['buttons', put_buttons(['A', 'B'], onclick=put_text)], # ..demo-only
  199. ['markdown', put_markdown('`Awesome PyWebIO!`')],
  200. ['file', put_file('hello.text', b'hello world')],
  201. ['table', put_table([['A', 'B'], ['C', 'D']])]
  202. ])
  203. The results of the above example are as follows:
  204. .. image:: /assets/put_table.png
  205. Similarly, you can pass ``put_xxx()`` calls to `popup() <pywebio.output.popup>` as the popup content:
  206. .. exportable-codeblock::
  207. :name: popup
  208. :summary: Popup
  209. popup('Popup title', [
  210. put_html('<h3>Popup Content</h3>'),
  211. 'plain html: <br/>', # Equivalent to: put_text('plain html: <br/>')
  212. put_table([['A', 'B'], ['C', 'D']]),
  213. put_button('close_popup()', onclick=close_popup)
  214. ])
  215. In addition, you can use `put_widget() <pywebio.output.put_widget>` to make your own output widgets that can accept ``put_xxx()`` calls.
  216. For a full list of functions that accept ``put_xxx()`` calls as content, see :ref:`Output functions list <output_func_list>`
  217. **Context Manager**
  218. Some output functions that accept ``put_xxx()`` calls as content can be used as context manager:
  219. .. exportable-codeblock::
  220. :name: output-context-manager
  221. :summary: Output as context manager
  222. with put_collapse('This is title'):
  223. for i in range(4):
  224. put_text(i)
  225. put_table([
  226. ['Commodity', 'Price'],
  227. ['Apple', '5.5'],
  228. ['Banana', '7'],
  229. ])
  230. For a full list of functions that support context manager, see :ref:`Output functions list <output_func_list>`
  231. .. _callback:
  232. Click Callback
  233. ^^^^^^^^^^^^^^^^
  234. As we can see from the above, the interaction of PyWebIO has two parts: input and output. The input function of PyWebIO
  235. is blocking, a form will be displayed on the user's web browser when calling input function, the input function will
  236. not return until the user submits the form. The output function is used to output content to the browser in real time.
  237. The input and output behavior of PyWebIO is consistent with the console program. That's why we say PyWebIO turning the
  238. browser into a "rich text terminal". So you can write PyWebIO applications in script programming way.
  239. In addition, PyWebIO also supports event callbacks: PyWebIO allows you to output some buttons and bind callbacks to them.
  240. The provided callback function will be executed when the button is clicked.
  241. This is an example:
  242. .. exportable-codeblock::
  243. :name: onclick-callback
  244. :summary: Event callback
  245. from functools import partial
  246. def edit_row(choice, row):
  247. put_text("You click %s button ar row %s" % (choice, row))
  248. put_table([
  249. ['Idx', 'Actions'],
  250. [1, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=1))],
  251. [2, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=2))],
  252. [3, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=3))],
  253. ])
  254. The call to `put_table() <pywebio.output.put_table>` will not block. When user clicks a button, the corresponding
  255. callback function will be invoked:
  256. .. image:: /assets/table_onclick.*
  257. Of course, PyWebIO also supports outputting individual button:
  258. .. exportable-codeblock::
  259. :name: put-buttons
  260. :summary: Event callback of button widget
  261. def btn_click(btn_val):
  262. put_text("You click %s button" % btn_val)
  263. put_buttons(['A', 'B', 'C'], onclick=btn_click) # a group of buttons
  264. put_button("Click me", onclick=lambda: toast("Clicked")) # single button
  265. In fact, all output can be bound to click events, not just buttons. You can call ``onclick()`` method after the output
  266. function (function name like ``put_xxx()``) call:
  267. .. exportable-codeblock::
  268. :name: onclick
  269. :summary: Click callback on any output
  270. put_image('some-image.png').onclick(lambda: toast('You click an image')) # ..doc-only
  271. put_image('https://www.python.org/static/img/python-logo.png').onclick(lambda: toast('You click an image')) # ..demo-only
  272. # set onclick in combined output
  273. put_table([
  274. ['Commodity', 'Price'],
  275. ['Apple', put_text('5.5').onclick(lambda: toast('You click the text'))],
  276. ])
  277. The return value of ``onclick()`` method is the object itself so it can be used in combined output.
  278. .. _output_scope:
  279. Output Scope
  280. ^^^^^^^^^^^^^^
  281. PyWebIO uses the scope model to give more control to the location of content output. The output scope is a container
  282. of output content. You can create a scope in somewhere and append content to it.
  283. Each output function (function name like ``put_xxx()``) will output its content to a scope, the default is "current scope".
  284. The "current scope" is set by `use_scope() <pywebio.output.use_scope>`.
  285. .. _use_scope:
  286. **use_scope()**
  287. You can use `use_scope() <pywebio.output.use_scope>` to open and enter a new output scope, or enter an existing output scope:
  288. .. exportable-codeblock::
  289. :name: use-scope
  290. :summary: use `use_scope()` to open or enter scope
  291. with use_scope('scope1'): # open and enter a new output: 'scope1'
  292. put_text('text1 in scope1') # output text to scope1
  293. put_text('text in parent scope of scope1') # output text to ROOT scope
  294. with use_scope('scope1'): # enter an existing scope: 'scope1'
  295. put_text('text2 in scope1') # output text to scope1
  296. The results of the above code are as follows::
  297. text1 in scope1
  298. text2 in scope1
  299. text in parent scope of scope1
  300. You can use ``clear`` parameter in `use_scope() <pywebio.output.use_scope>` to clear the existing content before entering the scope:
  301. .. exportable-codeblock::
  302. :name: use-scope-clear
  303. :summary: `use_scope()`'s `clear` parameter
  304. with use_scope('scope2'):
  305. put_text('create scope2')
  306. put_text('text in parent scope of scope2')
  307. ## ----
  308. with use_scope('scope2', clear=True): # enter the existing scope and clear the previous content
  309. put_text('text in scope2')
  310. The results of the above code are as follows::
  311. text in scope2
  312. text in parent scope of scope2
  313. `use_scope() <pywebio.output.use_scope>` can also be used as decorator:
  314. .. exportable-codeblock::
  315. :name: use-scope-decorator
  316. :summary: `use_scope()` as decorator
  317. import time # ..demo-only
  318. from datetime import datetime
  319. @use_scope('time', clear=True)
  320. def show_time():
  321. put_text(datetime.now())
  322. while 1: # ..demo-only
  323. show_time() # ..demo-only
  324. time.sleep(1) # ..demo-only
  325. When calling ``show_time()`` for the first time, a ``time`` scope will be created, and the current time will be output
  326. to it. And then every time the ``show_time()`` is called, the new content will replace the previous content.
  327. Scopes can be nested. At the beginning, PyWebIO applications have only one ``ROOT`` scope.
  328. You can create new scope in a scope. For example, the following code will create 3 scopes:
  329. .. exportable-codeblock::
  330. :name: use-scope-nested
  331. :summary: Nested Scope
  332. with use_scope('A'):
  333. put_text('Text in scope A')
  334. with use_scope('B'):
  335. put_text('Text in scope B')
  336. with use_scope('C'):
  337. put_text('Text in scope C')
  338. put_html("""<style> # ..demo-only
  339. #pywebio-scope-A {border: 1px solid red;} # ..demo-only
  340. #pywebio-scope-B {border: 1px solid blue;margin:2px} # ..demo-only
  341. #pywebio-scope-C {border: 1px solid green;margin-top:2px} # ..demo-only
  342. </style>""") # ..demo-only
  343. put_text() # ..demo-only
  344. put_buttons([('Put text to %s' % i, i) for i in ('A', 'B', 'C')], lambda s: put_text(s, scope=s)) # ..demo-only
  345. The above code will generate the following scope layout::
  346. โ”Œโ”€ROOTโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  347. โ”‚ โ”‚
  348. โ”‚ โ”Œโ”€Aโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
  349. โ”‚ โ”‚ Text in scope A โ”‚ โ”‚
  350. โ”‚ โ”‚ โ”Œโ”€Bโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
  351. โ”‚ โ”‚ โ”‚ Text in scope B โ”‚ โ”‚ โ”‚
  352. โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
  353. โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
  354. โ”‚ โ”‚
  355. โ”‚ โ”Œโ”€Cโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
  356. โ”‚ โ”‚ Text in scope C โ”‚ โ”‚
  357. โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
  358. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  359. .. _put_scope:
  360. **put_scope()**
  361. We already know that the scope is a container of output content. So can we use this container as a sub-item
  362. of a output (like, set a cell in table as a container)? Yes, you can use `put_scope() <pywebio.output.put_scope>` to
  363. create a scope explicitly.
  364. The function name starts with ``put_``, which means it can be pass to the functions that accept ``put_xxx()`` calls.
  365. .. exportable-codeblock::
  366. :name: put_scope
  367. :summary: `put_scope()`
  368. put_table([
  369. ['Name', 'Hobbies'],
  370. ['Tom', put_scope('hobby', content=put_text('Coding'))] # hobby is initialized to coding
  371. ])
  372. ## ----
  373. with use_scope('hobby', clear=True):
  374. put_text('Movie') # hobby is reset to Movie
  375. ## ----
  376. # append Music, Drama to hobby
  377. with use_scope('hobby'):
  378. put_text('Music')
  379. put_text('Drama')
  380. ## ----
  381. # insert the Coding into the top of the hobby
  382. put_markdown('**Coding**', scope='hobby', position=0)
  383. .. caution:: It is not allowed to have two scopes with the same name in the application.
  384. **Scope control**
  385. In addition to `use_scope() <pywebio.output.use_scope>` and `put_scope() <pywebio.output.put_scope>`,
  386. PyWebIO also provides the following scope control functions:
  387. * `clear(scope) <pywebio.output.clear>` : Clear the contents of the scope
  388. * `remove(scope) <pywebio.output.remove>` : Remove scope
  389. * `scroll_to(scope) <pywebio.output.scroll_to>` : Scroll the page to the scope
  390. Also, all output functions (function name like ``put_xxx()``) support a ``scope`` parameter to specify the destination
  391. scope to output, and support a ``position`` parameter to specify the insert position in target scope.
  392. Refer :ref:`output module <scope_param>` for more information.
  393. Layout
  394. ^^^^^^^^^^^^^^
  395. In general, using the output functions introduced above is enough to output what you want, but these outputs are arranged
  396. vertically. If you want to create a more complex layout (such as displaying a code block on the left side of the page
  397. and an image on the right), you need to use layout functions.
  398. The ``pywebio.output`` module provides 3 layout functions, and you can create complex layouts by combining them:
  399. * `put_row() <pywebio.output.put_row>` : Use row layout to output content. The content is arranged horizontally
  400. * `put_column() <pywebio.output.put_column>` : Use column layout to output content. The content is arranged vertically
  401. * `put_grid() <pywebio.output.put_grid>` : Output content using grid layout
  402. Here is an example by combining ``put_row()`` and ``put_column()``:
  403. .. exportable-codeblock::
  404. :name: put-row-column
  405. :summary: Layout functions
  406. put_row([
  407. put_column([
  408. put_code('A'),
  409. put_row([
  410. put_code('B1'), None, # None represents the space between the output
  411. put_code('B2'), None,
  412. put_code('B3'),
  413. ]),
  414. put_code('C'),
  415. ]), None,
  416. put_code('D'), None,
  417. put_code('E')
  418. ])
  419. The results of the above example are as follows:
  420. .. image:: /assets/layout.png
  421. :align: center
  422. The layout function also supports customizing the size of each part::
  423. put_row([put_image(...), put_image(...)], size='40% 60%') # The ratio of the width of two images is 2:3
  424. For more information, please refer to the :ref:`layout functions documentation <style_and_layout>`.
  425. .. _style:
  426. Style
  427. ^^^^^^^^^^^^^^
  428. If you are familiar with `CSS <https://en.wikipedia.org/wiki/CSS>`_ styles,
  429. you can use the ``style()`` method of output return to set a custom style for the output.
  430. You can set the CSS style for a single ``put_xxx()`` output:
  431. .. exportable-codeblock::
  432. :name: style-demo
  433. :summary: style of output
  434. put_text('hello').style('color: red; font-size: 20px')
  435. ## ----
  436. # in combined output
  437. put_row([
  438. put_text('hello').style('color: red'),
  439. put_markdown('markdown')
  440. ]).style('margin-top: 20px')
  441. The return value of ``style()`` method is the object itself so it can be used in combined output.
  442. .. _server_and_script_mode:
  443. Run application
  444. ----------------
  445. In PyWebIO, there are two modes to run PyWebIO applications: running as a script and using
  446. `pywebio.start_server() <pywebio.platform.tornado.start_server>` or
  447. `pywebio.platform.path_deploy() <pywebio.platform.path_deploy>` to run as a web service.
  448. Overview
  449. ^^^^^^^^^^^^^^
  450. .. _server_mode:
  451. **Server mode**
  452. In server mode, PyWebIO will start a web server to continuously provide services. When the user accesses the service
  453. address, PyWebIO will open a new session and run PyWebIO application in it.
  454. `start_server() <pywebio.platform.tornado.start_server>` is the most common way to start a web server to serve given
  455. PyWebIO applications::
  456. from pywebio import *
  457. def main(): # PyWebIO application function
  458. name = input.input("what's your name")
  459. output.put_text("hello", name)
  460. start_server(main, port=8080, debug=True)
  461. Now head over to http://127.0.0.1:8080/, and you should see your hello greeting.
  462. By using ``debug=True`` to enable debug mode, the server will automatically reload if code changes.
  463. The `start_server() <pywebio.platform.tornado.start_server>` provide a remote access support, when enabled
  464. (by passing `remote_access=True` to `start_server()`), you will get a public, shareable address for the current
  465. application, others can access your application in their browser via this address. Because the processing happens
  466. on your device (as long as your device stays on!), you don't have to worry about any dependencies.
  467. Using remote access makes it easy to temporarily share the application with others.
  468. Another way to deploy PyWebIO application as web service is using `path_deploy() <pywebio.platform.path_deploy>`.
  469. `path_deploy() <pywebio.platform.path_deploy>` is used to deploy the PyWebIO applications from a directory.
  470. Just define PyWebIO applications in python files under this directory, and you can access them via the path in the URL.
  471. Refer to :ref:`platform module <dir_deploy>` for more information.
  472. .. attention::
  473. Note that in Server mode, all functions from ``pywebio.input``, ``pywebio.output`` and ``pywebio.session`` modules can only be called in
  474. the context of PyWebIO application functions. For example, the following code is **not allowed**::
  475. import pywebio
  476. from pywebio.input import input
  477. port = input('Input port number:') # โŒ error
  478. pywebio.start_server(my_task_func, port=int(port))
  479. **Script mode**
  480. If you never call ``start_server()`` or ``path_deploy()`` in your code, then you are running PyWebIO application as script mode.
  481. In script mode, a web browser page will be open automatically when running to the first call to PyWebIO interactive functions,
  482. and all subsequent PyWebIO interactions will take place on this page. When the script exit, the page will be inactive.
  483. If the user closes the browser before the script exiting, then subsequent calls to PyWebIO's interactive functions
  484. will cause a `SessionException <pywebio.exceptions.SessionException>` exception.
  485. .. _thread_in_server_mode:
  486. Concurrent
  487. ^^^^^^^^^^^^^^
  488. PyWebIO can be used in a multi-threading environment.
  489. **Script mode**
  490. In script mode, you can freely start new thread and call PyWebIO interactive functions in it.
  491. When all `non-daemonic <https://docs.python.org/3/library/threading.html#thread-objects>`_ threads finish running, the script exits.
  492. **Server mode**
  493. In server mode, if you need to use PyWebIO interactive functions in new thread, you need to use
  494. `pywebio.session.register_thread(thread) <pywebio.session.register_thread>` to register the new thread
  495. (so that PyWebIO can know which session the thread belongs to). If the PyWebIO interactive function is not used in
  496. the new thread, no registration is required. Threads that are not registered with
  497. `register_thread(thread) <pywebio.session.register_thread>` calling PyWebIO's interactive functions will cause
  498. `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>`.
  499. Example of using multi-threading in Server mode::
  500. def show_time():
  501. while True:
  502. with use_scope(name='time', clear=True):
  503. put_text(datetime.datetime.now())
  504. time.sleep(1)
  505. def app():
  506. t = threading.Thread(target=show_time)
  507. register_thread(t)
  508. put_markdown('## Clock')
  509. t.start() # run `show_time()` in background
  510. # โŒ this thread will cause `SessionNotFoundException`
  511. threading.Thread(target=show_time).start()
  512. put_text('Background task started.')
  513. start_server(app, port=8080, debug=True)
  514. .. _session_close:
  515. Close of session
  516. ^^^^^^^^^^^^^^^^^
  517. When user close the browser page, the session will be closed. After the browser page is closed, PyWebIO input function
  518. calls that have not yet returned in the current session will cause `SessionClosedException <pywebio.exceptions.SessionClosedException>`,
  519. and subsequent calls to PyWebIO interactive functions will cause `SessionNotFoundException <pywebio.exceptions.SessionNotFoundException>`
  520. or `SessionClosedException <pywebio.exceptions.SessionClosedException>`.
  521. 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.
  522. You can use `pywebio.session.defer_call(func) <pywebio.session.defer_call>` to set the function to be called when the
  523. session closes. `defer_call(func) <pywebio.session.defer_call>` can be used for resource cleaning. You can call
  524. `defer_call(func) <pywebio.session.defer_call>` multiple times in the session, and the set functions will be executed
  525. sequentially after the session closes.
  526. More about PyWebIO
  527. ---------------------
  528. By now, you already get the most important features of PyWebIO and can start to write awesome PyWebIO applications.
  529. However, there are some other useful features we don't cover in the above. Here we just make a briefly explain about them.
  530. When you need them in your application, you can refer to their document.
  531. Also, :doc:`here </cookbook>` is a cookbook where you can find some useful code snippets for your PyWebIO application.
  532. ``session`` module
  533. ^^^^^^^^^^^^^^^^^^^^
  534. The :doc:`pywebio.session </session>` module give you more control to session.
  535. * Use `set_env() <pywebio.session.set_env>` to configure the title, page appearance, input panel and so on for current session.
  536. * The `info <pywebio.session.info>` object provides a lot information about the current session,
  537. such as the user IP address, user language and user browser information.
  538. * `local <pywebio.session.local>` is a session-local storage, it used to save data whose values are session specific.
  539. * `run_js() <pywebio.session.run_js>` let you execute JavaScript code in user's browser,
  540. and `eval_js() <pywebio.session.eval_js>` let you execute JavaScript expression and get the value of it.
  541. ``pin`` module
  542. ^^^^^^^^^^^^^^^^^^^^
  543. As you already know, the input function of PyWebIO is blocking and the input form will be destroyed after successful submission.
  544. In some cases, you may want to make the input form not disappear after submission, and can continue to receive input.
  545. So PyWebIO provides the :doc:`pywebio.pin </pin>` module to achieve persistent input by pinning input widgets to the page.
  546. ``platform`` module
  547. ^^^^^^^^^^^^^^^^^^^^
  548. The :doc:`pywebio.platform </platform>` module provides support for deploying PyWebIO applications in different ways.
  549. There are two protocols (WebSocket and HTTP) can be used in server to communicates with the browser. The WebSocket is
  550. used by default. If you want to use HTTP protocol, you can choose other ``start_server()`` functions in this module.
  551. You might want to set some web page related configuration (such as SEO information, js and css injection) for your PyWebIO application,
  552. `pywebio.config() <pywebio.config>` can be helpful.
  553. Advanced features
  554. ^^^^^^^^^^^^^^^^^^^^
  555. The PyWebIO application can be integrated into an existing Python web project, the PyWebIO application and the web
  556. project share a web framework. Refer to :ref:`Advanced Topic: Integration with Web Framework <integration_web_framework>`
  557. for more information.
  558. PyWebIO also provides support for coroutine-based sessions. Refer to :ref:`Advanced Topic: Coroutine-based session <coroutine_based_session>`
  559. for more information.
  560. If you try to bundles your PyWebIO application into a stand-alone executable file, to make users can run the application
  561. without installing a Python interpreter or any modules, you might want to refer to :ref:`Libraries support: Build stand-alone App <stand_alone_app>`
  562. If you want to make some data visualization in your PyWebIO application, you can't miss :ref:`Libraries support: Data visualization <visualization>`
  563. Last but not least
  564. ---------------------
  565. This is basically all features of PyWebIO, you can continue to read the rest of the documents, or start writing your PyWebIO applications now.
  566. Finally, please allow me to provide one more suggestion. When you encounter a design problem when using PyWebIO, you can
  567. ask yourself a question: What would I do if it is in a terminal program?
  568. If you already have the answer, it can be done in the same way with PyWebIO. If the problem persists or the solution is
  569. not good enough, you can consider the :ref:`callback mechanism <callback>` or :doc:`pin <./pin>` module.
  570. OK, Have fun with PyWebIO!