Преглед изворни кода

add cookbook chapter in doc

wangweimin пре 3 година
родитељ
комит
f4f698df69
9 измењених фајлова са 205 додато и 6 уклоњено
  1. 1 1
      .drone.yml
  2. 1 1
      .github/workflows/lint.yml
  3. 2 1
      .github/workflows/sync_repo.yml
  4. 2 1
      docs/conf.py
  5. 168 0
      docs/cookbook.rst
  6. 1 1
      docs/index.rst
  7. 12 0
      docs/static/pywebio.css
  8. 12 0
      pywebio/input.py
  9. 6 1
      requirements.txt

+ 1 - 1
.drone.yml

@@ -26,5 +26,5 @@ steps:
       - >
         docker run --restart=always --name=pywebio-demos -v $PWD:/app_tmp
         --label="traefik.http.services.pywebiodemos.loadbalancer.server.port=80"
-        -d python:3 bash -c "cp -r /app_tmp /app && cd /app && pip3 install . && python3 -m demos --port=80"
+        -d python:3 bash -c "cp -r /app_tmp /app && cd /app && pip3 install . && pip3 install -r requirements.txt && python3 -m demos --port=80"
       - sleep 5  # wait container start

+ 1 - 1
.github/workflows/lint.yml

@@ -20,7 +20,7 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install -r requirements.txt
+          pip install -e ".[all]"
       - name: Lint with flake8
         run: |
           pip install flake8

+ 2 - 1
.github/workflows/sync_repo.yml

@@ -26,7 +26,8 @@ jobs:
       - name: Build doc demos
         run: |
           pip3 install -e ".[all]"
-          cd docs && CODE_EXPORT_PATH=../demos/doc_demos make clean text
+          pip3 install -r requirements.txt
+          cd docs && CODE_EXPORT_PATH=../demos/doc_demos make clean html
       - name: Set dev version
         run: python3 tools/build_dev_version.py
       - name: Push

+ 2 - 1
docs/conf.py

@@ -33,7 +33,8 @@ extensions = [
     "sphinx.ext.viewcode",
     'sphinx_tabs.tabs',
     'sphinx.ext.extlinks',
-    'codeblock'
+    'codeblock',
+    'sphinx_toolbox.collapse',
 ]
 
 primary_domain = "py"

+ 168 - 0
docs/cookbook.rst

@@ -0,0 +1,168 @@
+Cookbook
+==========================
+
+.. contents::
+   :local:
+
+Interaction related
+----------------------------------------------------------------------------------------------
+
+Equivalent to "Press any key to continue"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. exportable-codeblock::
+    :name: cookbook-press-anykey-continue
+    :summary: Press any key to continue
+
+    actions(buttons=["Continue"])
+    put_text("Go next")  # ..demo-only
+
+
+Output pandas dataframe
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. exportable-codeblock::
+    :name: cookbook-pandas-df
+    :summary: Output pandas dataframe
+
+    import numpy as np
+    import pandas as pd
+
+    df = pd.DataFrame(np.random.randn(6, 4), columns=list("ABCD"))
+    put_html(df.to_html(border=0))
+
+.. seealso:: `pandas.DataFrame.to_html — pandas documentation <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html#pandas-dataframe-to-html>`_
+
+Output Matplotlib figure
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Simply do not call ``matplotlib.pyplot.show``, directly save the figure to in-memory buffer and output the buffer
+via :func:`pywebio.output.put_image`:
+
+.. exportable-codeblock::
+    :name: cookbook-matplotlib
+    :summary: Output Matplotlib plot
+
+    import matplotlib
+    import matplotlib.pyplot as plt
+    import io
+    import pywebio
+
+    matplotlib.use('agg')  # required, use a non-interactive backend
+
+    fig, ax = plt.subplots()  # Create a figure containing a single axes.
+    ax.plot([1, 2, 3, 4], [1, 4, 2, 3])  # Plot some data on the axes.
+
+    buf = io.BytesIO()
+    fig.savefig(buf)
+    pywebio.output.put_image(buf.getvalue())
+
+The ``matplotlib.use('agg')`` is required so that the server does not try to create (and then destroy) GUI windows
+that will never be seen.
+
+When using Matplotlib in a web server (multiple threads environment), pyplot may cause some conflicts in some cases,
+read the following articles for more information:
+
+    * `Multi Threading in Python and Pyplot | by Ranjitha Korrapati | Medium <https://medium.com/@ranjitha.korrapati/multi-threading-in-python-and-pyplot-46f325e6a9d0>`_
+
+    * `Embedding in a web application server (Flask) — Matplotlib documentation <https://matplotlib.org/stable/gallery/user_interfaces/web_application_server_sgskip.html>`_
+
+
+Blocking confirm model
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. collapse:: Code
+
+    .. exportable-codeblock::
+        :name: cookbook-confirm-model
+        :summary: Blocking confirm model
+
+        import threading
+        from pywebio import output
+
+        def confirm(title, content=None, timeout=None):
+            """Show a confirm model.
+
+            :param str title: Model title.
+            :param list/put_xxx() content: Model content.
+            :param None/float timeout: Seconds for operation time out.
+            :return: Return `True` when the "CONFIRM" button is clicked,
+                return `False` when the "CANCEL" button is clicked,
+                return `None` when a timeout is given and the operation times out.
+            """
+            if not isinstance(content, list):
+                content = [content]
+
+            event = threading.Event()
+            result = None
+
+            def onclick(val):
+                nonlocal result
+                result = val
+                event.set()
+
+            content.append(output.put_buttons([
+                {'label': 'CONFIRM', 'value': True},
+                {'label': 'CANCEL', 'value': False, 'color': 'danger'},
+            ], onclick=onclick))
+            output.popup(title=title, content=content, closable=False)
+
+            event.wait(timeout=timeout)  # wait the model buttons are clicked
+            output.close_popup()
+            return result
+
+
+        res = confirm('Confirm', 'You have 5 seconds to make s choice', timeout=5)
+        output.put_text("Your choice is:", res)
+
+
+
+Web application related
+----------------------------------------------------------------------------------------------
+
+Get URL parameters of current page
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can use URL parameter (known also as "query strings" or "URL query parameters") to pass information to your web
+application. In PyWebIO application, you can use the following code to get the URL parameters as a Python dict.
+
+.. exportable-codeblock::
+    :name: cookbook-url-query
+    :summary: Get URL parameters of current page
+
+    # `query` is a dict
+    query = eval_js("Object.fromEntries(new URLSearchParams(window.location.search))")
+    put_text(query)
+
+
+Add Google AdSense/Analytics code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When you setup Google AdSense/Analytics, you will get a javascript file and a piece of code that needs to be inserted
+into your application page, you can use :func:`pywebio.config()` to inject js file and code to your PyWebIO application::
+
+    from pywebio import start_server, output, config
+
+    js_file = "https://www.googletagmanager.com/gtag/js?id=G-xxxxxxx"
+    js_code = """
+    window.dataLayer = window.dataLayer || [];
+    function gtag(){dataLayer.push(arguments);}
+    gtag('js', new Date());
+
+    gtag('config', 'G-xxxxxxx');
+    """
+
+    @config(js_file=js_file, js_code=js_code)
+    def main():
+        output.put_text("hello world")
+
+    start_server(main, port=8080)
+
+
+Refresh page on connection lost
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Add the following code to the beginning of your PyWebIO application main function::
+
+    session.run_js('WebIO._state.CurrentSession.on_session_close(()=>{setTimeout(()=>location.reload(), 4000})')
+

+ 1 - 1
docs/index.rst

@@ -94,7 +94,7 @@ This documentation is also available in `PDF and Epub formats <https://readthedo
 .. toctree::
    :titlesonly:
 
-   FAQ
+   cookbook
    releases
 
 .. toctree::

+ 12 - 0
docs/static/pywebio.css

@@ -44,4 +44,16 @@ td .line-block {
     top: 4px;
     padding-left: 0px;
     background-color: #f8f8f8;
+}
+
+details {
+    margin-bottom: 24px;
+}
+
+/*Adjust ``.. contents::`` style */
+.contents li>p{
+    margin-bottom: 0px!important;
+}
+.contents ul{
+    margin-bottom: 8px!important;
 }

+ 12 - 0
pywebio/input.py

@@ -590,6 +590,18 @@ def file_upload(label='', accept=None, name=None, placeholder='Choose file', mul
         :func:`path_deploy() <pywebio.platform.path_deploy>` to start the PyWebIO application,
         the maximum file size to be uploaded allowed by the web framework can be set through the ``max_payload_size`` parameter.
 
+    .. exportable-codeblock::
+        :name: file_upload_example
+        :summary: `file_upload()` example
+
+        # Upload a file and save to server                      # ..doc-only
+        f = input.file_upload("Upload a file")                  # ..doc-only
+        open('asset/'+f['filename'], 'wb').write(f['content'])  # ..doc-only
+
+        imgs = file_upload("Select some pictures:", accept="image/*", multiple=True)
+        for img in imgs:
+            put_image(img['content'])
+
     """
     item_spec, valid_func, onchange_func = _parse_args(locals())
     item_spec['type'] = 'file'

+ 6 - 1
requirements.txt

@@ -23,4 +23,9 @@ coverage
 # doc building requirements
 sphinx==3.*
 sphinx-tabs
-sphinx-rtd-theme==0.4.*
+sphinx-rtd-theme==0.4.*
+sphinx-toolbox==2.15.0
+
+# demo running requirements
+numpy
+matplotlib