Documentation for all official extensions
This commit is contained in:
84
docs/api.rst
84
docs/api.rst
@@ -4,93 +4,72 @@ API Reference
|
|||||||
``microdot`` module
|
``microdot`` module
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
The ``microdot`` module defines a few classes that help implement HTTP-based
|
|
||||||
servers for MicroPython and standard Python, with multithreading support for
|
|
||||||
Python interpreters that support it.
|
|
||||||
|
|
||||||
``Microdot`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot.Microdot
|
.. autoclass:: microdot.Microdot
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
``Request`` class
|
|
||||||
~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot.Request
|
.. autoclass:: microdot.Request
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
``Response`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot.Response
|
.. autoclass:: microdot.Response
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
``MultiDict`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot.MultiDict
|
.. autoclass:: microdot.MultiDict
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
``microdot_asyncio`` module
|
``microdot_asyncio`` module
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
The ``microdot_asyncio`` module defines a few classes that help implement
|
|
||||||
HTTP-based servers for MicroPython and standard Python that use ``asyncio``
|
|
||||||
and coroutines.
|
|
||||||
|
|
||||||
``Microdot`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot_asyncio.Microdot
|
.. autoclass:: microdot_asyncio.Microdot
|
||||||
:inherited-members:
|
:inherited-members:
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
``Request`` class
|
|
||||||
~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot_asyncio.Request
|
.. autoclass:: microdot_asyncio.Request
|
||||||
:inherited-members:
|
:inherited-members:
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
``Response`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot_asyncio.Response
|
.. autoclass:: microdot_asyncio.Response
|
||||||
:inherited-members:
|
:inherited-members:
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
``microdot_utemplate`` module
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: microdot_utemplate
|
||||||
|
:members:
|
||||||
|
|
||||||
|
``microdot_jinja`` module
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. automodule:: microdot_jinja
|
||||||
|
:members:
|
||||||
|
|
||||||
|
``microdot_session`` module
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: microdot_session
|
||||||
|
:members:
|
||||||
|
|
||||||
``microdot_test_client`` module
|
``microdot_test_client`` module
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
The ``microdot_test_client`` module defines a test client that can be used to
|
|
||||||
create automated tests for the Microdot server.
|
|
||||||
|
|
||||||
``TestClient`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot_test_client.TestClient
|
.. autoclass:: microdot_test_client.TestClient
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
``TestResponse`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot_test_client.TestResponse
|
.. autoclass:: microdot_test_client.TestResponse
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
``microdot_asyncio_test_client`` module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. autoclass:: microdot_asyncio_test_client.TestClient
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autoclass:: microdot_asyncio_test_client.TestResponse
|
||||||
|
:members:
|
||||||
|
|
||||||
``microdot_wsgi`` module
|
``microdot_wsgi`` module
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
The ``microdot_wsgi`` module provides an extended ``Microdot`` class that
|
|
||||||
implements the WSGI protocol and can be used with a compliant WSGI web server
|
|
||||||
such as `Gunicorn <https://gunicorn.org/>`_ or
|
|
||||||
`uWSGI <https://uwsgi-docs.readthedocs.io/en/latest/>`_. Since there are
|
|
||||||
no WSGI web servers available for MicroPython, this support is currently
|
|
||||||
limited to standard Python.
|
|
||||||
|
|
||||||
``Microdot`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot_wsgi.Microdot
|
.. autoclass:: microdot_wsgi.Microdot
|
||||||
:members:
|
:members:
|
||||||
:exclude-members: shutdown, run
|
:exclude-members: shutdown, run
|
||||||
@@ -98,15 +77,6 @@ limited to standard Python.
|
|||||||
``microdot_asgi`` module
|
``microdot_asgi`` module
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
The ``microdot_asgi`` module provides an extended ``Microdot`` class that
|
|
||||||
implements the ASGI protocol and can be used with a compliant ASGI server such
|
|
||||||
as `Uvicorn <https://www.uvicorn.org/>`_. Since there are no ASGI web servers
|
|
||||||
available for MicroPython, this support is currently limited to standard
|
|
||||||
Python.
|
|
||||||
|
|
||||||
``Microdot`` class
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: microdot_asgi.Microdot
|
.. autoclass:: microdot_asgi.Microdot
|
||||||
:members:
|
:members:
|
||||||
:exclude-members: shutdown, run
|
:exclude-members: shutdown, run
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, os.path.abspath('../src'))
|
sys.path.insert(0, os.path.abspath('../src'))
|
||||||
|
sys.path.insert(1, os.path.abspath('../libs/common'))
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,13 @@ Asynchronous Support with ``asyncio``
|
|||||||
- | CPython: None
|
- | CPython: None
|
||||||
| MicroPython: `uasyncio <https://github.com/micropython/micropython/tree/master/extmod/uasyncio>`_
|
| MicroPython: `uasyncio <https://github.com/micropython/micropython/tree/master/extmod/uasyncio>`_
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `hello_async.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello_async.py>`_
|
||||||
|
|
||||||
Microdot can be extended to use an asynchronous programming model based on the
|
Microdot can be extended to use an asynchronous programming model based on the
|
||||||
``asyncio`` package. When the :class:`Microdot <microdot_asyncio.Microdot>`
|
``asyncio`` package. When the :class:`Microdot <microdot_asyncio.Microdot>`
|
||||||
class is imported from the ``microdot_asyncio`` package, an asynchronous server
|
class is imported from the ``microdot_asyncio`` package, an asynchronous server
|
||||||
is used.
|
is used, and handlers can be defined as coroutines.
|
||||||
|
|
||||||
The example that follows uses ``asyncio`` coroutines for concurrency::
|
The example that follows uses ``asyncio`` coroutines for concurrency::
|
||||||
|
|
||||||
@@ -42,8 +45,14 @@ The example that follows uses ``asyncio`` coroutines for concurrency::
|
|||||||
Rendering HTML Templates
|
Rendering HTML Templates
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Many web applications use HTML templates for rendering content to clients.
|
||||||
|
Microdot includes extensions to render templates with the
|
||||||
|
`utemplate <https://github.com/pfalcon/utemplate>`_ package on CPython and
|
||||||
|
MicroPython, and with `Jinja <https://jinja.palletsprojects.com/>`_ only on
|
||||||
|
CPython.
|
||||||
|
|
||||||
Using the uTemplate Engine
|
Using the uTemplate Engine
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
:align: left
|
:align: left
|
||||||
@@ -58,6 +67,32 @@ Using the uTemplate Engine
|
|||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | `utemplate <https://github.com/pfalcon/utemplate/tree/master/utemplate>`_
|
- | `utemplate <https://github.com/pfalcon/utemplate/tree/master/utemplate>`_
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `hello_utemplate.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello_utemplate.py>`_
|
||||||
|
| `hello_utemplate_async.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello_utemplate_async.py>`_
|
||||||
|
|
||||||
|
The :func:`render_template <microdot_utemplate.render_template>` function is
|
||||||
|
used to render HTML templates with the uTemplate engine. The first argument is
|
||||||
|
the template filename, relative to the templates directory, which is
|
||||||
|
*templates* by default. Any additional arguments are passed to the template
|
||||||
|
engine to be used as arguments.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from microdot_utemplate import render_template
|
||||||
|
|
||||||
|
@app.get('/')
|
||||||
|
def index(req):
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
The default location from where templates are loaded is the *templates*
|
||||||
|
subdirectory. This location can be changed with the
|
||||||
|
:func:`init_templates <microdot_utemplate.init_templates>` function::
|
||||||
|
|
||||||
|
from microdot_utemplate import init_templates
|
||||||
|
|
||||||
|
init_templates('my_templates')
|
||||||
|
|
||||||
Using the Jinja Engine
|
Using the Jinja Engine
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
@@ -74,6 +109,34 @@ Using the Jinja Engine
|
|||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | `Jinja2 <https://jinja.palletsprojects.com/>`_
|
- | `Jinja2 <https://jinja.palletsprojects.com/>`_
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `hello_jinja.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello_jinja.py>`_
|
||||||
|
|
||||||
|
The :func:`render_template <microdot_jinja.render_template>` function is used
|
||||||
|
to render HTML templates with the Jinja engine. The first argument is the
|
||||||
|
template filename, relative to the templates directory, which is *templates* by
|
||||||
|
default. Any additional arguments are passed to the template engine to be used
|
||||||
|
as arguments.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from microdot_jinja import render_template
|
||||||
|
|
||||||
|
@app.get('/')
|
||||||
|
def index(req):
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
The default location from where templates are loaded is the *templates*
|
||||||
|
subdirectory. This location can be changed with the
|
||||||
|
:func:`init_templates <microdot_jinja.init_templates>` function::
|
||||||
|
|
||||||
|
from microdot_jinja import init_templates
|
||||||
|
|
||||||
|
init_templates('my_templates')
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The Jinja extension is not compatible with MicroPython.
|
||||||
|
|
||||||
Maintaing Secure User Sessions
|
Maintaing Secure User Sessions
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -89,11 +152,64 @@ Maintaing Secure User Sessions
|
|||||||
|
|
||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | CPython: `PyJWT <https://pyjwt.readthedocs.io/>`_
|
- | CPython: `PyJWT <https://pyjwt.readthedocs.io/>`_
|
||||||
| MicroPython: `ujwt.py <https://github.com/miguelgrinberg/micropython-lib/blob/ujwt-module/python-ecosys/ujwt/ujwt.py>`_,
|
| MicroPython: `jwt.py <https://github.com/miguelgrinberg/micropython-lib/blob/ujwt-module/python-ecosys/ujwt/ujwt.py>`_,
|
||||||
`hmac <https://github.com/micropython/micropython-lib/blob/master/python-stdlib/hmac/hmac.py>`_,
|
`hmac <https://github.com/micropython/micropython-lib/blob/master/python-stdlib/hmac/hmac.py>`_,
|
||||||
`hashlib <https://github.com/miguelgrinberg/micropython-lib/blob/ujwt-module/python-stdlib/hashlib>`_,
|
`hashlib <https://github.com/miguelgrinberg/micropython-lib/blob/ujwt-module/python-stdlib/hashlib>`_,
|
||||||
`warnings <https://github.com/micropython/micropython-lib/blob/master/python-stdlib/warnings/warnings.py>`_
|
`warnings <https://github.com/micropython/micropython-lib/blob/master/python-stdlib/warnings/warnings.py>`_
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `login.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/login.py>`_
|
||||||
|
|
||||||
|
The session extension provides a secure way for the application to maintain
|
||||||
|
user sessions. The session is stored as a signed cookie in the client's
|
||||||
|
browser, in `JSON Web Token (JWT) <https://en.wikipedia.org/wiki/JSON_Web_Token>`_
|
||||||
|
format.
|
||||||
|
|
||||||
|
To work with user sessions, the application first must configure the secret key
|
||||||
|
that will be used to sign the session cookies. It is very important that this
|
||||||
|
key is kept secret. An attacker who is in possession of this key can generate
|
||||||
|
valid user session cookies with any contents.
|
||||||
|
|
||||||
|
To set the secret key, use the :func:`set_session_secret_key <microdot_session.set_session_secret_key>` function::
|
||||||
|
|
||||||
|
from microdot_session import set_session_secret_key
|
||||||
|
|
||||||
|
set_session_secret_key('top-secret!')
|
||||||
|
|
||||||
|
To :func:`get_session <microdot_session.get_session>`,
|
||||||
|
:func:`update_session <microdot_session.update_session>` and
|
||||||
|
:func:`delete_session <microdot_session.delete_session>` functions are used
|
||||||
|
inside route handlers to retrieve, store and delete session data respectively.
|
||||||
|
The :func:`with_session <microdot_session.with_session>` decorator is provided
|
||||||
|
as a convenient way to retrieve the session at the start of a route handler.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from microdot import Microdot
|
||||||
|
from microdot_session import set_session_secret_key, with_session, \
|
||||||
|
update_session, delete_session
|
||||||
|
|
||||||
|
app = Microdot()
|
||||||
|
set_session_secret_key('top-secret')
|
||||||
|
|
||||||
|
@app.route('/', methods=['GET', 'POST'])
|
||||||
|
@with_session
|
||||||
|
def index(req, session):
|
||||||
|
username = session.get('username')
|
||||||
|
if req.method == 'POST':
|
||||||
|
username = req.form.get('username')
|
||||||
|
update_session(req, {'username': username})
|
||||||
|
return redirect('/')
|
||||||
|
if username is None:
|
||||||
|
return 'Not logged in'
|
||||||
|
else:
|
||||||
|
return 'Logged in as ' + username
|
||||||
|
|
||||||
|
@app.post('/logout')
|
||||||
|
def logout(req):
|
||||||
|
delete_session(req)
|
||||||
|
return redirect('/')
|
||||||
|
|
||||||
Test Client
|
Test Client
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -110,9 +226,69 @@ Test Client
|
|||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | None
|
- | None
|
||||||
|
|
||||||
|
The Microdot Test Client is a utility class that can be used during testing to
|
||||||
|
send requests into the application.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from microdot import Microdot
|
||||||
|
from microdot_test_client import TestClient
|
||||||
|
|
||||||
|
app = Microdot()
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index(req):
|
||||||
|
return 'Hello, World!'
|
||||||
|
|
||||||
|
def test_app():
|
||||||
|
client = TestClient(app)
|
||||||
|
response = client.get('/')
|
||||||
|
assert response.text == 'Hello, World!'
|
||||||
|
|
||||||
|
See the documentation for the :class:`TestClient <microdot_test_client.TestClient>`
|
||||||
|
class for more details.
|
||||||
|
|
||||||
|
Asynchronous Test Client
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
* - Compatibility
|
||||||
|
- | CPython & MicroPython
|
||||||
|
|
||||||
|
* - Required Microdot source files
|
||||||
|
- | `microdot.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot.py>`_
|
||||||
|
| `microdot_asyncio.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot_asyncio.py>`_
|
||||||
|
| `microdot_test_client.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot_test_client.py>`_
|
||||||
|
| `microdot_asyncio_test_client.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot_asyncio_test_client.py>`_
|
||||||
|
|
||||||
|
* - Required external dependencies
|
||||||
|
- | None
|
||||||
|
|
||||||
|
Similar to the :class:`TestClient <microdot_test_client.TestClient>` class
|
||||||
|
above, but for asynchronous applications.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
from microdot_asyncio_test_client import TestClient
|
||||||
|
|
||||||
|
async def test_app():
|
||||||
|
client = TestClient(app)
|
||||||
|
response = await client.get('/')
|
||||||
|
assert response.text == 'Hello, World!'
|
||||||
|
|
||||||
|
See the :class:`reference documentation <microdot_asyncio_test_client.TestClient>`
|
||||||
|
for details.
|
||||||
|
|
||||||
Deploying on a Production Web Server
|
Deploying on a Production Web Server
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The ``Microdot`` class creates its own simple web server. This is enough for an
|
||||||
|
application deployed with MicroPython, but when using CPython it may be useful
|
||||||
|
to use a separate, battle-tested web server. To address this need, Microdot
|
||||||
|
provides extensions that implement the WSGI and ASGI protocols.
|
||||||
|
|
||||||
Using a WSGI Web Server
|
Using a WSGI Web Server
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
@@ -129,6 +305,34 @@ Using a WSGI Web Server
|
|||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | A WSGI web server, such as `Gunicorn <https://gunicorn.org/>`_.
|
- | A WSGI web server, such as `Gunicorn <https://gunicorn.org/>`_.
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `hello_wsgi.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello_wsgi.py>`_
|
||||||
|
|
||||||
|
|
||||||
|
The ``microdot_wsgi`` module provides an extended ``Microdot`` class that
|
||||||
|
implements the WSGI protocol and can be used with a compliant WSGI web server
|
||||||
|
such as `Gunicorn <https://gunicorn.org/>`_ or
|
||||||
|
`uWSGI <https://uwsgi-docs.readthedocs.io/en/latest/>`_.
|
||||||
|
|
||||||
|
To use a WSGI web server, the application must import the
|
||||||
|
:class:`Microdot <microdot_wsgi.Microdot>` class from the ``microdot_wsgi``
|
||||||
|
module::
|
||||||
|
|
||||||
|
from microdot_wsgi import Microdot
|
||||||
|
|
||||||
|
app = Microdot()
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index(req):
|
||||||
|
return 'Hello, World!'
|
||||||
|
|
||||||
|
The ``app`` application instance created from this class is a WSGI application
|
||||||
|
that can be used with any complaint WSGI web server. If the above application
|
||||||
|
is stored in a file called *test.py*, then the following command runs the
|
||||||
|
web application using the Gunicorn web server::
|
||||||
|
|
||||||
|
gunicorn test:app
|
||||||
|
|
||||||
Using an ASGI Web Server
|
Using an ASGI Web Server
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
@@ -146,3 +350,29 @@ Using an ASGI Web Server
|
|||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | An ASGI web server, such as `Uvicorn <https://uvicorn.org/>`_.
|
- | An ASGI web server, such as `Uvicorn <https://uvicorn.org/>`_.
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `hello_asgi.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello_asgi.py>`_
|
||||||
|
|
||||||
|
The ``microdot_asgi`` module provides an extended ``Microdot`` class that
|
||||||
|
implements the ASGI protocol and can be used with a compliant ASGI server such
|
||||||
|
as `Uvicorn <https://www.uvicorn.org/>`_.
|
||||||
|
|
||||||
|
To use an ASGI web server, the application must import the
|
||||||
|
:class:`Microdot <microdot_asgi.Microdot>` class from the ``microdot_asgi``
|
||||||
|
module::
|
||||||
|
|
||||||
|
from microdot_asgi import Microdot
|
||||||
|
|
||||||
|
app = Microdot()
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
async def index(req):
|
||||||
|
return 'Hello, World!'
|
||||||
|
|
||||||
|
The ``app`` application instance created from this class is an ASGI application
|
||||||
|
that can be used with any complaint ASGI web server. If the above application
|
||||||
|
is stored in a file called *test.py*, then the following command runs the
|
||||||
|
web application using the Uvicorn web server::
|
||||||
|
|
||||||
|
uvicorn test:app
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ Running with CPython
|
|||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | None
|
- | None
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `hello.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello.py>`_
|
||||||
|
|
||||||
When using CPython, you can start the web server by running the script that
|
When using CPython, you can start the web server by running the script that
|
||||||
defines and runs the application instance::
|
defines and runs the application instance::
|
||||||
|
|
||||||
@@ -89,6 +92,10 @@ Running with MicroPython
|
|||||||
* - Required external dependencies
|
* - Required external dependencies
|
||||||
- | None
|
- | None
|
||||||
|
|
||||||
|
* - Examples
|
||||||
|
- | `hello.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello.py>`_
|
||||||
|
| `gpio.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/gpio.py>`_
|
||||||
|
|
||||||
When using MicroPython, you can upload a *main.py* file containing the web
|
When using MicroPython, you can upload a *main.py* file containing the web
|
||||||
server code to your device along with *microdot.py*. MicroPython will
|
server code to your device along with *microdot.py*. MicroPython will
|
||||||
automatically run *main.py* when the device is powered on, so the web server
|
automatically run *main.py* when the device is powered on, so the web server
|
||||||
@@ -618,8 +625,8 @@ Example::
|
|||||||
return {'hello': 'world'}
|
return {'hello': 'world'}
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
JSON responses are sent with the ``Content-Type`` header set to
|
A ``Content-Type`` header set to ``application/json`` is automatically added
|
||||||
``application/json``.
|
to the response.
|
||||||
|
|
||||||
Redirects
|
Redirects
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
@@ -694,9 +701,9 @@ default content type::
|
|||||||
Setting Cookies
|
Setting Cookies
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Many web application rely on cookies to maintain client state between requests.
|
Many web applications rely on cookies to maintain client state between
|
||||||
Cookies can be set with the ``Set-Cookie`` header in the response, but since
|
requests. Cookies can be set with the ``Set-Cookie`` header in the response,
|
||||||
this is such a common practice, Microdot provides the
|
but since this is such a common practice, Microdot provides the
|
||||||
:func:`set_cookie() <microdot.Response.set_cookie>` method in the response
|
:func:`set_cookie() <microdot.Response.set_cookie>` method in the response
|
||||||
object to add a properly formatted cookie header to the response.
|
object to add a properly formatted cookie header to the response.
|
||||||
|
|
||||||
@@ -719,7 +726,7 @@ Another option is to create a response object directly in the route function::
|
|||||||
|
|
||||||
@app.get('/')
|
@app.get('/')
|
||||||
def index(request):
|
def index(request):
|
||||||
response = Response('Hello, World!'))
|
response = Response('Hello, World!')
|
||||||
response.set_cookie('name', 'value')
|
response.set_cookie('name', 'value')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,15 @@ def init_templates(template_dir='templates'):
|
|||||||
|
|
||||||
|
|
||||||
def render_template(template, *args, **kwargs):
|
def render_template(template, *args, **kwargs):
|
||||||
|
"""Render a template.
|
||||||
|
|
||||||
|
:param template: The filename of the template to render, relative to the
|
||||||
|
configured template directory.
|
||||||
|
:param args: Positional arguments to be passed to the render engine.
|
||||||
|
:param kwargs: Keyword arguments to be passed to the render engine.
|
||||||
|
|
||||||
|
The return value is a string with the rendered template.
|
||||||
|
"""
|
||||||
if _jinja_env is None: # pragma: no cover
|
if _jinja_env is None: # pragma: no cover
|
||||||
init_templates()
|
init_templates()
|
||||||
template = _jinja_env.get_template(template)
|
template = _jinja_env.get_template(template)
|
||||||
|
|||||||
@@ -4,11 +4,22 @@ secret_key = None
|
|||||||
|
|
||||||
|
|
||||||
def set_session_secret_key(key):
|
def set_session_secret_key(key):
|
||||||
|
"""Set the secret key for signing user sessions.
|
||||||
|
|
||||||
|
:param key: The secret key, as a string or bytes object.
|
||||||
|
"""
|
||||||
global secret_key
|
global secret_key
|
||||||
secret_key = key
|
secret_key = key
|
||||||
|
|
||||||
|
|
||||||
def get_session(request):
|
def get_session(request):
|
||||||
|
"""Retrieve the user session.
|
||||||
|
|
||||||
|
:param request: The client request.
|
||||||
|
|
||||||
|
The return value is a dictionary with the data stored in the user's
|
||||||
|
session, or ``{}`` if the session data is not available or invalid.
|
||||||
|
"""
|
||||||
global secret_key
|
global secret_key
|
||||||
if not secret_key:
|
if not secret_key:
|
||||||
raise ValueError('The session secret key is not configured')
|
raise ValueError('The session secret key is not configured')
|
||||||
@@ -24,6 +35,14 @@ def get_session(request):
|
|||||||
|
|
||||||
|
|
||||||
def update_session(request, session):
|
def update_session(request, session):
|
||||||
|
"""Update the user session.
|
||||||
|
|
||||||
|
:param request: The client request.
|
||||||
|
:param session: A dictionary with the update session data for the user.
|
||||||
|
|
||||||
|
Calling this function adds a cookie with the updated session to the request
|
||||||
|
currently being processed.
|
||||||
|
"""
|
||||||
if not secret_key:
|
if not secret_key:
|
||||||
raise ValueError('The session secret key is not configured')
|
raise ValueError('The session secret key is not configured')
|
||||||
|
|
||||||
@@ -36,6 +55,13 @@ def update_session(request, session):
|
|||||||
|
|
||||||
|
|
||||||
def delete_session(request):
|
def delete_session(request):
|
||||||
|
"""Remove the user session.
|
||||||
|
|
||||||
|
:param request: The client request.
|
||||||
|
|
||||||
|
Calling this function adds a cookie removal header to the request currently
|
||||||
|
being processed.
|
||||||
|
"""
|
||||||
@request.after_request
|
@request.after_request
|
||||||
def _delete_session(request, response):
|
def _delete_session(request, response):
|
||||||
response.set_cookie('session', '', http_only=True,
|
response.set_cookie('session', '', http_only=True,
|
||||||
@@ -44,6 +70,19 @@ def delete_session(request):
|
|||||||
|
|
||||||
|
|
||||||
def with_session(f):
|
def with_session(f):
|
||||||
|
"""Decorator that passes the user session to the route handler.
|
||||||
|
|
||||||
|
The session dictionary is passed to the decorated function as an argument
|
||||||
|
after the request object. Example::
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
@with_session
|
||||||
|
def index(request, session):
|
||||||
|
return 'Hello, World!'
|
||||||
|
|
||||||
|
Note that the decorator does not save the session. To update the session,
|
||||||
|
call the :func:`update_session <microdot_session.update_session>` function.
|
||||||
|
"""
|
||||||
def wrapper(request, *args, **kwargs):
|
def wrapper(request, *args, **kwargs):
|
||||||
return f(request, get_session(request), *args, **kwargs)
|
return f(request, get_session(request), *args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,15 @@ def init_templates(template_dir='templates', loader_class=recompile.Loader):
|
|||||||
|
|
||||||
|
|
||||||
def render_template(template, *args, **kwargs):
|
def render_template(template, *args, **kwargs):
|
||||||
|
"""Render a template.
|
||||||
|
|
||||||
|
:param template: The filename of the template to render, relative to the
|
||||||
|
configured template directory.
|
||||||
|
:param args: Positional arguments to be passed to the render engine.
|
||||||
|
:param kwargs: Keyword arguments to be passed to the render engine.
|
||||||
|
|
||||||
|
The return value is an iterator that returns sections of rendered template.
|
||||||
|
"""
|
||||||
if _loader is None: # pragma: no cover
|
if _loader is None: # pragma: no cover
|
||||||
init_templates()
|
init_templates()
|
||||||
render = _loader.load(template)
|
render = _loader.load(template)
|
||||||
|
|||||||
Reference in New Issue
Block a user