Documentation updates

This commit is contained in:
Miguel Grinberg
2022-06-04 16:41:02 +01:00
parent d71665fd38
commit bcbad51675
6 changed files with 74 additions and 31 deletions

View File

@@ -60,3 +60,31 @@ and coroutines.
:inherited-members:
:members:
``microdot_wsgi`` module
------------------------
The ``microdot_wsgi`` module provides an extended ``Microdot`` class that
implements the WSGI protocol and can be used with a complaint WSGI web server
such as `Gunicorn <https://gunicorn.org/>`_ or
`uWSGI <https://uwsgi-docs.readthedocs.io/en/latest/>`_.
``Microdot`` class
~~~~~~~~~~~~~~~~~~
.. autoclass:: microdot_wsgi.Microdot
:members:
:exclude-members: shutdown, run
``microdot_asgi`` module
------------------------
The ``microdot_asgi`` module provides an extended ``Microdot`` class that
implements the ASGI protocol and can be used with a complaint ASGI server such
as `Uvicorn <https://www.uvicorn.org/>`_.
``Microdot`` class
~~~~~~~~~~~~~~~~~~
.. autoclass:: microdot_asgi.Microdot
:members:
:exclude-members: shutdown, run

View File

@@ -5,8 +5,12 @@ Microdot can be installed with ``pip``::
pip install microdot
For platforms that do not support or cannot run ``pip``, you can also manually
copy and install the ``microdot.py`` and ``microdot_asyncio.py`` source files.
For MicroPython, you can install with ``upip``.
On platforms where ``pip`` or ``upip`` are not viable options, you can manually
copy and install the ``microdot.py`` and ``microdot_asyncio.py`` source files
from the `GitHub reposutory <https://github.com/miguelgrinberg/microdot>`_
into your project directory.
Examples
--------

View File

@@ -352,7 +352,10 @@ class Response():
"""An HTTP response class.
:param body: The body of the response. If a dictionary or list is given,
a JSON formatter is used to generate the body.
a JSON formatter is used to generate the body. If a file-like
object or a generator is given, a streaming response is used.
If a string is given, it is encoded from UTF-8. Else, the
body should be a byte sequence.
:param status_code: The numeric HTTP status code of the response. The
default is 200.
:param headers: A dictionary of headers to include in the response.

View File

@@ -44,7 +44,12 @@ class _BodyStream: # pragma: no cover
class Microdot(BaseMicrodot):
def __init__(self):
super().__init__()
self.embedded_server = False
async def asgi_app(self, scope, receive, send):
"""An ASGI application."""
if scope['type'] != 'http': # pragma: no cover
return
path = scope['path']
@@ -120,18 +125,17 @@ class Microdot(BaseMicrodot):
return await self.asgi_app(scope, receive, send)
def shutdown(self):
pid = os.getpgrp() if hasattr(os, 'getpgrp') else os.getpid()
os.kill(pid, signal.SIGTERM)
if self.embedded_server: # pragma: no cover
super().shutdown()
else:
pid = os.getpgrp() if hasattr(os, 'getpgrp') else os.getpid()
os.kill(pid, signal.SIGTERM)
def run(self, host='0.0.0.0', port=5000, debug=False,
**options): # pragma: no cover
try:
import uvicorn
except ImportError: # pragma: no cover
raise RuntimeError('The run() method requires uvicorn to be '
'installed (i.e. run "pip install uvicorn").')
self.debug = debug
if 'log_level' not in options:
options['log_level'] = 'info' if debug else 'error'
uvicorn.run(self, host=host, port=port, **options)
"""Normally you would not start the server by invoking this method.
Instead, start your chosen ASGI web server and pass the ``Microdot``
instance as the ASGI application.
"""
self.embedded_server = True
super().run(host=host, port=port, debug=debug, **options)

View File

@@ -107,7 +107,10 @@ class Response(BaseResponse):
"""An HTTP response class.
:param body: The body of the response. If a dictionary or list is given,
a JSON formatter is used to generate the body.
a JSON formatter is used to generate the body. If a file-like
object or an async generator is given, a streaming response is
used. If a string is given, it is encoded from UTF-8. Else,
the body should be a byte sequence.
:param status_code: The numeric HTTP status code of the response. The
default is 200.
:param headers: A dictionary of headers to include in the response.

View File

@@ -1,4 +1,3 @@
import logging
import os
import signal
from microdot import * # noqa: F401, F403
@@ -7,7 +6,12 @@ from microdot import Request
class Microdot(BaseMicrodot):
def __init__(self):
super().__init__()
self.embedded_server = False
def wsgi_app(self, environ, start_response):
"""A WSGI application callable."""
path = environ.get('SCRIPT_NAME', '') + environ.get('PATH_INFO', '')
if 'QUERY_STRING' in environ and environ['QUERY_STRING']:
path += '?' + environ['QUERY_STRING']
@@ -39,20 +43,17 @@ class Microdot(BaseMicrodot):
return self.wsgi_app(environ, start_response)
def shutdown(self):
pid = os.getpgrp() if hasattr(os, 'getpgrp') else os.getpid()
os.kill(pid, signal.SIGTERM)
if self.embedded_server: # pragma: no cover
super().shutdown()
else:
pid = os.getpgrp() if hasattr(os, 'getpgrp') else os.getpid()
os.kill(pid, signal.SIGTERM)
def run(self, host='0.0.0.0', port=5000, debug=False,
**options): # pragma: no cover
try:
from waitress import serve
except ImportError: # pragma: no cover
raise RuntimeError('The run() method requires Waitress to be '
'installed (i.e. run "pip install waitress").')
self.debug = debug
if debug:
logger = logging.getLogger('waitress')
logger.setLevel(logging.INFO)
serve(self, host=host, port=port, **options)
"""Normally you would not start the server by invoking this method.
Instead, start your chosen WSGI web server and pass the ``Microdot``
instance as the WSGI callable.
"""
self.embedded_server = True
super().run(host=host, port=port, debug=debug, **options)