guide.rst 31 KB

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