Skip to content

Commit

Permalink
Add readthedocs documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
unknown authored and TheClockTwister committed Mar 12, 2021
2 parents 09bffbf + 74e1045 commit fa2c23d
Show file tree
Hide file tree
Showing 21 changed files with 356 additions and 90 deletions.
38 changes: 21 additions & 17 deletions Aeros/Request.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
"""
Top module doc string
This module contains the wrapper for `Quart.request` that can be used inside web methods
"""

from quart import request
import functools


class EasyRequest:
""" A helper class that make request handling easier
""" A helper class that makes request handling more uniform.
All attributes are assessable via the same syntax, while with Flask.request
or quart.request, you will have slightly different syntax when retrieving
different request attributes.
different request attributes, which can be very irritating and take much
time debugging your code for missing parentheses or an await statement.
.. hint::
You only need to await attributes that need calculation, for example
Expand All @@ -24,20 +24,22 @@ class EasyRequest:
params = EasyRequest.params
form = await EasyRequest.form # requires time for calculation
json = await EasyRequest.json # requires time for calculation
"""

params: dict = ...
""" The URL parameters like Flask.request.params. """

headers: dict = ...
""" The request headers like Flask.request.headers. """
""" The request headers like quart.request.headers. """

cookies: dict = ...
""" The request cookies like quart.request.cookies. """

__quart_request: request = ...
""" The Flask.request. instance that is used in the current scope. """
""" The quart.request. instance that is used in the current scope. """

def __load(self):
""" loads the content of Flask.request into this instance and returns it. """
""" Loads the content of quart.request into this instance and returns it. """

self.__quart_request = request
self.params = dict(self.__quart_request.args)
Expand All @@ -46,7 +48,9 @@ def __load(self):
return self

def __call__(self, f):
""" Decorates an endpoint function to use the EasyRequest with. """
""" Decorates an endpoint function to use the `EasyRequest` with, which makes
`EasyRequest` available in that endpoint method.
"""

@functools.wraps(f)
async def decorated_function(*args2, **kwargs2):
Expand All @@ -57,24 +61,24 @@ async def decorated_function(*args2, **kwargs2):

@property
async def form(self):
""" The request form data like Flask.request.form. """

""" The request form data like quart.request.form. """
return dict(await self.__quart_request.form)

@property
async def json(self):
""" The request body data (as JSON) like Flask.request.form.
""" The request body data (as JSON) like quart.request.form.
Be aware that in order for Flask.request.get_json() to return
a JSON dictionary, the ``Content-Type`` header must be set to
``application/json``.
Be aware that in order for quart.request.get_json() to return
a JSON dictionary, the `Content-Type` header must be set to
`application/json`.
"""
json = await self.__quart_request.get_json()
return {} if json is None else json


if __name__ == '__main__':
from Aeros import WebServer, render_template, jsonify
from Aeros import WebServer
from quart import jsonify, render_template
from time import strftime

app = WebServer(__name__, host="0.0.0.0", port=80) # init backend & web server
Expand All @@ -97,4 +101,4 @@ async def current_time():
return jsonify({"timestamp": strftime("%H:%M:%S")})


app.run_server() # run web server in this thread (endless mode)
app.run() # run web server in this thread (endless mode)
26 changes: 12 additions & 14 deletions Aeros/WebServer.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
"""
Main web server instance
This module contains the main web server class
"""

import functools
import inspect
from quart import Quart
import hashlib
import uvicorn
import logging
import logging.handlers
from logging import INFO
import sys

from .caching.server import Cache
from .compression import Base
from .Request import EasyRequest
import logging
import logging.handlers


class WebServer(Quart):
""" This is the main server class which extends a standard Flask class by a bunch of features and major
performance improvements. It extends the Quart class, which by itself is already an enhanced version of
the Flask class. This class however allows production-grade deployment using the hypercorn WSGI server
as production server. But instead of calling the hypercorn command via the console, it can be started
performance improvements. It extends the quart class, which by itself is already an enhanced version of
the Flask class. This class however allows production-grade deployment using the uvicorn ASGI server
as production server. But instead of calling the uvicorn command via the console, it can be started
directly from the Python code itself, making it easier to integrate in higher-level scripts and
applications without calling os.system() od subprocess.Popen(). """
applications without calling os.system() or subprocess.Popen().
"""

__log_format_std = '[%(asctime)s] %(levelname)s: %(message)s' # for instance logger "quart.app"

Expand Down Expand Up @@ -51,8 +52,8 @@ def __init__(self, import_name: str, host: str = "0.0.0.0", port: int = 80, incl

def cache(self, timeout=None, key_prefix="view/%s", unless=None, forced_update=None,
response_filter=None, query_string=False, hash_method=hashlib.md5, cache_none=False, ):
""" A simple wrapper that forwards cached() decorator to the internal
Cache() instance. May be used as the normal @cache.cached() decorator. """
""" A simple wrapper that forwards the cached() decorator to the internal Cache() instance.
May be used as the normal @cache.cached() decorator."""

def decorator(f):
if self._cache is None:
Expand All @@ -71,6 +72,7 @@ async def decorated_function(*args2, **kwargs2):
return decorator

def clear_cache(self):
""" Clears the WebServer instance cache. Use with caution!"""
self._cache.clear()

def _get_own_instance_path(self) -> str:
Expand Down Expand Up @@ -185,11 +187,7 @@ def run_server(self,
del config['workers']
self.logger.info(f"Starting in single-thread mode...")

x = config.get('app')
del config['app']
print(x)

uvicorn.run(x, **config)
uvicorn.run(**config)

def run(self, *args, **kwargs):
return self.run_server(*args, **kwargs, suppress_deprecation_warning=True)
Expand Down
2 changes: 1 addition & 1 deletion Aeros/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
from .misc import *
from .Request import EasyRequest
from .thread import AdvancedThread
from .compression import Compression
from .compression import Gzip, Br
from .caching import *
4 changes: 4 additions & 0 deletions Aeros/caching/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module contains features for server-side and client-side caching.
"""

from .server import (
SimpleCache,
FileSystemCache,
Expand Down
17 changes: 17 additions & 0 deletions Aeros/caching/client.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
"""
This module contains features for client-side caching using the Cache-Control header.
"""

from enum import Enum
from quart import Response
import functools
from quart import make_response


class CacheTypes(Enum):
"""
An enum to replace the cache option strings with variables for auto-complete in most IDEs.
"""
NO_CACHE = 'no-cache'
NO_STORE = 'no-store'
PUBLIC = 'public'
PRIVATE = 'private'


class CacheControl:
"""
This class manipulates the Cache-Control header in all responses sent from an endpoint
decorated with this class.
.. hint::
If you need conditional caching rules you may still use `response` from quart to
manipulate the Cache-Control header to your needs.
"""

def __init__(
self, cache_type: CacheTypes, max_age: int = None,
immutable: bool = False, no_transform: bool = False,
Expand All @@ -26,6 +42,7 @@ def __init__(
immutable (bool): If set, browsers will not re-validate
stale_while_revalidate (int): Time in seconds how long we allow to serve the old content while re-validating
stale_if_error (bool): Serve the last cached content if backend gives error code
cache_on_status (list): A list of HTTP response codes when to apply the policy (default: [200])
"""
self.cache_on_status = cache_on_status
Expand Down
17 changes: 17 additions & 0 deletions Aeros/caching/server.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
"""
This module contains features for server-side caching by wrapping the `flask_caching` module.
"""

from flask_caching import Cache
import warnings


class SimpleCache(Cache):
""" The most basic cache that requires no set-up and no arguments. """

def __new__(cls, *args, **kwargs):
return Cache(
*args, **kwargs,
Expand All @@ -12,6 +18,9 @@ def __new__(cls, *args, **kwargs):


class FileSystemCache(Cache):
""" Stores cached responses on the file system,
good for huge caches that don't fit into memory."""

def __new__(cls, directory: str, *args, **kwargs):
return Cache(
*args, **kwargs,
Expand All @@ -23,6 +32,12 @@ def __new__(cls, directory: str, *args, **kwargs):

# For backwards compatibility
class FilesystemCache:
""" An alias for `FileSystemCache`
.. warning::
This class is deprecated! Use `FileSystemCache` instead.
"""

def __new__(cls, *args, **kwargs):
warnings.warn('"FilesystemCache" is deprecated! Use "FileSystemCache" instead.')
return FileSystemCache(
Expand All @@ -31,6 +46,8 @@ def __new__(cls, *args, **kwargs):


class RedisCache(Cache):
""" A Redis client to store responses on an external Redis server. """

# ignore different signature
def __new__(cls, host: str, port: int, user: str, password: str, db: str, *args, **kwargs):
return Cache(
Expand Down
38 changes: 33 additions & 5 deletions Aeros/compression.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
"""
The compression module includes classes for compression algorithms implemented by `quart_compress`.
These are compatible with the async coroutine framework that Aeros uses and will compress the web
server's responses before sending it to the client.
"""

from typing import List
from quart_compress import Compress
from quart import Quart
import warnings


class Base:
"""
The base class that implements the wrapper for `quart_compress.Compress`.
"""
algorithm = 'gzip'

def __init__(self, level: int = 2, min_size: int = 500, mimetypes: List = None):
Expand All @@ -14,6 +23,12 @@ def __init__(self, level: int = 2, min_size: int = 500, mimetypes: List = None):
self.mimetypes = mimetypes if mimetypes else ['text/plain', 'text/html', 'text/css', 'text/scss', 'text/xml', 'application/json', 'application/javascript']

def init_app(self, app: Quart):
"""
Initializes the `Compress` instance with the give `WebServer`/`Quart` application instance
Arguments:
app (Quart): The web server instance to use the caching functionality with
"""
app.config["COMPRESS_ALGORITHM"] = self.algorithm
app.config["COMPRESS_MIN_SIZE"] = self.min_size
app.config["COMPRESS_LEVEL"] = self.level
Expand All @@ -23,14 +38,27 @@ def init_app(self, app: Quart):


class Gzip(Base):
"""
This class should be used to implement a Gzip compression to your Aeros web server.
"""
algorithm = 'gzip'


class Br(Base):
"""
This class should be used to implement a Br compression to your Aeros web server.
"""
algorithm = 'br'


class Compression:
def __new__(cls, *args, **kwargs):
warnings.warn('"Compression" is deprecated. Please use "Gzip" or "Br"!')
return Gzip(*args, **kwargs)
"""
The former class that represented compression for Aeros. Falls back to `Gzip`.
.. warning::
This class is deprecated and should not be used. Use `Gzip` or `Br` instead.
"""

class Br(Base):
algorithm = 'br'
def __new__(cls, *args, **kwargs):
warnings.warn('"Compression" is deprecated. Please use "Gzip" or "Br" instead.')
return Gzip(*args, **kwargs)
6 changes: 5 additions & 1 deletion Aeros/misc.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
from quart import jsonify, render_template
"""
The misc module contains useful helper functions and decorators to simplify development and make
the resulting code much more readable and clean.
"""

from asgiref.sync import sync_to_async, async_to_sync
Empty file removed Aeros/patches/__init__.py
Empty file.
1 change: 0 additions & 1 deletion Aeros/patches/quart/__init__.py

This file was deleted.

6 changes: 0 additions & 6 deletions Aeros/patches/quart/app.py

This file was deleted.

17 changes: 0 additions & 17 deletions Aeros/patches/quart/asgi.py

This file was deleted.

0 comments on commit fa2c23d

Please sign in to comment.