fastapi-startkit 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi_startkit/__init__.py +3 -0
- fastapi_startkit/application.py +40 -0
- fastapi_startkit/configuration/Configuration.py +80 -0
- fastapi_startkit/configuration/__init__.py +2 -0
- fastapi_startkit/configuration/helpers.py +5 -0
- fastapi_startkit/configuration/providers/ConfigurationProvider.py +16 -0
- fastapi_startkit/configuration/providers/__init__.py +1 -0
- fastapi_startkit/container/__init__.py +1 -0
- fastapi_startkit/container/container.py +494 -0
- fastapi_startkit/environment/environment.py +76 -0
- fastapi_startkit/exceptions/DD.py +38 -0
- fastapi_startkit/exceptions/ExceptionHandler.py +76 -0
- fastapi_startkit/exceptions/__init__.py +38 -0
- fastapi_startkit/exceptions/exceptionite/__init__.py +0 -0
- fastapi_startkit/exceptions/exceptionite/blocks.py +101 -0
- fastapi_startkit/exceptions/exceptionite/controllers.py +13 -0
- fastapi_startkit/exceptions/exceptionite/solutions.py +66 -0
- fastapi_startkit/exceptions/exceptionite/tabs.py +19 -0
- fastapi_startkit/exceptions/exceptions.py +218 -0
- fastapi_startkit/exceptions/handlers/DumpExceptionHandler.py +104 -0
- fastapi_startkit/exceptions/handlers/HttpExceptionHandler.py +28 -0
- fastapi_startkit/exceptions/handlers/ModelNotFoundHandler.py +13 -0
- fastapi_startkit/facades/Auth.py +5 -0
- fastapi_startkit/facades/Auth.pyi +32 -0
- fastapi_startkit/facades/Broadcast.py +5 -0
- fastapi_startkit/facades/Cache.py +5 -0
- fastapi_startkit/facades/Config.py +5 -0
- fastapi_startkit/facades/Config.pyi +14 -0
- fastapi_startkit/facades/Dump.py +5 -0
- fastapi_startkit/facades/Dump.pyi +26 -0
- fastapi_startkit/facades/Facade.py +5 -0
- fastapi_startkit/facades/Gate.py +5 -0
- fastapi_startkit/facades/Gate.pyi +32 -0
- fastapi_startkit/facades/Hash.py +5 -0
- fastapi_startkit/facades/Hash.pyi +28 -0
- fastapi_startkit/facades/Loader.py +5 -0
- fastapi_startkit/facades/Loader.pyi +30 -0
- fastapi_startkit/facades/Mail.py +5 -0
- fastapi_startkit/facades/Mail.pyi +14 -0
- fastapi_startkit/facades/Notification.py +5 -0
- fastapi_startkit/facades/Notification.pyi +25 -0
- fastapi_startkit/facades/Queue.py +5 -0
- fastapi_startkit/facades/Queue.pyi +10 -0
- fastapi_startkit/facades/RateLimiter.py +5 -0
- fastapi_startkit/facades/RateLimiter.pyi +43 -0
- fastapi_startkit/facades/Request.py +5 -0
- fastapi_startkit/facades/Request.pyi +88 -0
- fastapi_startkit/facades/Response.py +5 -0
- fastapi_startkit/facades/Response.pyi +68 -0
- fastapi_startkit/facades/Session.py +5 -0
- fastapi_startkit/facades/Session.pyi +59 -0
- fastapi_startkit/facades/Storage.py +5 -0
- fastapi_startkit/facades/Storage.pyi +12 -0
- fastapi_startkit/facades/Url.py +5 -0
- fastapi_startkit/facades/Url.pyi +22 -0
- fastapi_startkit/facades/View.py +5 -0
- fastapi_startkit/facades/View.pyi +54 -0
- fastapi_startkit/facades/__init__.py +19 -0
- fastapi_startkit/loader/Loader.py +78 -0
- fastapi_startkit/loader/__init__.py +1 -0
- fastapi_startkit/providers/ConfigurationProvider.py +13 -0
- fastapi_startkit/providers/Provider.py +14 -0
- fastapi_startkit/providers/__init__.py +4 -0
- fastapi_startkit/utils/__init__.py +0 -0
- fastapi_startkit/utils/collections.py +545 -0
- fastapi_startkit/utils/console.py +39 -0
- fastapi_startkit/utils/data/mime.types +1863 -0
- fastapi_startkit/utils/filesystem.py +100 -0
- fastapi_startkit/utils/http.py +101 -0
- fastapi_startkit/utils/location.py +90 -0
- fastapi_startkit/utils/str.py +120 -0
- fastapi_startkit/utils/structures.py +97 -0
- fastapi_startkit/utils/time.py +58 -0
- fastapi_startkit-0.1.0.dist-info/METADATA +13 -0
- fastapi_startkit-0.1.0.dist-info/RECORD +76 -0
- fastapi_startkit-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from ...utils.filesystem import get_module_dir
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def is_property(obj):
|
|
8
|
+
return not inspect.ismethod(obj)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def is_local(obj_name, obj):
|
|
12
|
+
return (
|
|
13
|
+
not obj_name.startswith("__")
|
|
14
|
+
and not obj_name.endswith("__")
|
|
15
|
+
and not type(obj).__name__ == "builtin_function_or_method"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def serialize_property(obj):
|
|
20
|
+
if isinstance(obj, list):
|
|
21
|
+
local_list = []
|
|
22
|
+
for subobj in obj:
|
|
23
|
+
local_list.append(serialize_property(subobj))
|
|
24
|
+
return local_list
|
|
25
|
+
elif isinstance(obj, dict):
|
|
26
|
+
local_dict = {}
|
|
27
|
+
for key, val in obj.items():
|
|
28
|
+
local_dict.update({key: serialize_property(val)})
|
|
29
|
+
return local_dict
|
|
30
|
+
elif hasattr(obj, "serialize"):
|
|
31
|
+
return obj.serialize()
|
|
32
|
+
else:
|
|
33
|
+
return str(obj)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DumpExceptionHandler:
|
|
37
|
+
def __init__(self, application):
|
|
38
|
+
self.application = application
|
|
39
|
+
|
|
40
|
+
self.assets_path = os.path.join(
|
|
41
|
+
get_module_dir(__file__), "../../templates/assets"
|
|
42
|
+
)
|
|
43
|
+
self.styles = []
|
|
44
|
+
self.scripts = []
|
|
45
|
+
|
|
46
|
+
def add_style(self, file):
|
|
47
|
+
with open(os.path.join(self.assets_path, file), "r") as f:
|
|
48
|
+
self.styles.append(f.read())
|
|
49
|
+
|
|
50
|
+
def add_script(self, file):
|
|
51
|
+
with open(os.path.join(self.assets_path, file), "r") as f:
|
|
52
|
+
self.scripts.append(f.read())
|
|
53
|
+
|
|
54
|
+
def get_scripts(self):
|
|
55
|
+
scripts_str = ""
|
|
56
|
+
for script in self.scripts:
|
|
57
|
+
scripts_str += f"<script>{script}</script>\n"
|
|
58
|
+
return scripts_str
|
|
59
|
+
|
|
60
|
+
def get_styles(self):
|
|
61
|
+
styles_str = ""
|
|
62
|
+
for style in self.styles:
|
|
63
|
+
styles_str += f"<style>{style}</style>\n"
|
|
64
|
+
return styles_str
|
|
65
|
+
|
|
66
|
+
def handle(self, exception):
|
|
67
|
+
dumps = []
|
|
68
|
+
# for dump in self.application.make("dumper").get_dumps():
|
|
69
|
+
# for obj_name, obj in dump.objects.items():
|
|
70
|
+
# all_members = inspect.getmembers(obj, predicate=inspect.ismethod)
|
|
71
|
+
# all_properties = inspect.getmembers(obj, predicate=is_property)
|
|
72
|
+
# members = {
|
|
73
|
+
# name: str(member)
|
|
74
|
+
# for name, member in all_members
|
|
75
|
+
# if is_local(name, member)
|
|
76
|
+
# }
|
|
77
|
+
# properties = {
|
|
78
|
+
# name: serialize_property(prop)
|
|
79
|
+
# for name, prop in all_properties
|
|
80
|
+
# if is_local(name, prop)
|
|
81
|
+
# }
|
|
82
|
+
# dumps.append(
|
|
83
|
+
# {
|
|
84
|
+
# "name": obj_name,
|
|
85
|
+
# "obj": str(obj),
|
|
86
|
+
# "members": members,
|
|
87
|
+
# "properties": properties,
|
|
88
|
+
# }
|
|
89
|
+
# )
|
|
90
|
+
dumps = self.application.make("dumper").get_serialized_dumps()
|
|
91
|
+
self.add_style("tailwind.css")
|
|
92
|
+
self.add_style("github-dark.min.css")
|
|
93
|
+
self.add_script("highlight.min.js")
|
|
94
|
+
|
|
95
|
+
return self.application.make("response").view(
|
|
96
|
+
self.application.make("view").render(
|
|
97
|
+
"/masonite/templates/dump",
|
|
98
|
+
{
|
|
99
|
+
"styles": self.get_styles(),
|
|
100
|
+
"scripts": self.get_scripts(),
|
|
101
|
+
"dumps": dumps,
|
|
102
|
+
},
|
|
103
|
+
)
|
|
104
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class HttpExceptionHandler:
|
|
2
|
+
def __init__(self, application):
|
|
3
|
+
self.application = application
|
|
4
|
+
|
|
5
|
+
def handle(self, exception):
|
|
6
|
+
status_code = exception.get_status()
|
|
7
|
+
view_name = f"errors/{status_code}"
|
|
8
|
+
response = self.application.make("response")
|
|
9
|
+
request = self.application.make("request")
|
|
10
|
+
|
|
11
|
+
if request.accepts_json():
|
|
12
|
+
payload = {
|
|
13
|
+
"status": exception.get_status(),
|
|
14
|
+
"message": exception.get_response(),
|
|
15
|
+
}
|
|
16
|
+
return response.json(payload, status_code)
|
|
17
|
+
|
|
18
|
+
# Renders HTTP exception as HTML with predefined error page if exists
|
|
19
|
+
if self.application.make("view").exists(view_name):
|
|
20
|
+
return response.view(
|
|
21
|
+
self.application.make("view").render(
|
|
22
|
+
f"errors/{status_code}", {"message": exception.get_response()}
|
|
23
|
+
),
|
|
24
|
+
status_code,
|
|
25
|
+
)
|
|
26
|
+
else:
|
|
27
|
+
# Else render the exception without using template
|
|
28
|
+
return response.view(exception.get_response(), status_code)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from ..exceptions import ModelNotFoundException
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ModelNotFoundHandler:
|
|
5
|
+
def __init__(self, application):
|
|
6
|
+
self.application = application
|
|
7
|
+
|
|
8
|
+
def handle(self, exception):
|
|
9
|
+
masonite_exception = ModelNotFoundException(
|
|
10
|
+
"No record found with the given primary key"
|
|
11
|
+
)
|
|
12
|
+
self.application.make("response").status(404)
|
|
13
|
+
self.application.make("exception_handler").handle(masonite_exception)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Tuple, List
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..routes import Route
|
|
5
|
+
|
|
6
|
+
class Auth:
|
|
7
|
+
"""Authentication facade."""
|
|
8
|
+
|
|
9
|
+
def add_guard(name: str, guard: Any): ...
|
|
10
|
+
def set_configuration(config: dict): ...
|
|
11
|
+
def guard(guard: Any) -> "Auth": ...
|
|
12
|
+
def get_guard(name: str = None) -> Any: ...
|
|
13
|
+
def get_config_options(guard: Any = None) -> dict: ...
|
|
14
|
+
def attempt(email: str, password: str, once: bool = False) -> Any: ...
|
|
15
|
+
def attempt_by_id(user_id: int, once: bool = False) -> Any: ...
|
|
16
|
+
def logout(self) -> "Auth":
|
|
17
|
+
"""Logout the current authenticated user."""
|
|
18
|
+
...
|
|
19
|
+
def user(self) -> Any:
|
|
20
|
+
"""Get the current authenticated user."""
|
|
21
|
+
...
|
|
22
|
+
def register(dictionary: dict) -> Any:
|
|
23
|
+
""""""
|
|
24
|
+
...
|
|
25
|
+
def password_reset(email: str) -> "Tuple[None, None]|Tuple[int,str]":
|
|
26
|
+
"""Reset password of the user with the given email."""
|
|
27
|
+
...
|
|
28
|
+
def reset_password(password: str, token: str) -> bool:
|
|
29
|
+
"""Reset password of the user with the given authentication token."""
|
|
30
|
+
...
|
|
31
|
+
@classmethod
|
|
32
|
+
def routes(self) -> List[Route]: ...
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
class Config:
|
|
4
|
+
"""Configuration facades to manage Masonite config files."""
|
|
5
|
+
|
|
6
|
+
def get(key: str, default: None) -> Any:
|
|
7
|
+
"""Get given key in config, can use a dotted path."""
|
|
8
|
+
...
|
|
9
|
+
def set(key: str, value: Any) -> None:
|
|
10
|
+
"""Override config for given key."""
|
|
11
|
+
...
|
|
12
|
+
def all(self) -> dict:
|
|
13
|
+
"""Get all config object."""
|
|
14
|
+
...
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Any, List, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..dumps import Dump as DumpObject
|
|
5
|
+
|
|
6
|
+
class Dump:
|
|
7
|
+
"""Dumper facade."""
|
|
8
|
+
|
|
9
|
+
def clear(self) -> "Dump":
|
|
10
|
+
"""Clear all dumped data"""
|
|
11
|
+
...
|
|
12
|
+
def dd(*objects: List[Any]):
|
|
13
|
+
"""Dump all provided args and die, raising a DumpException."""
|
|
14
|
+
...
|
|
15
|
+
def dump(*objects: List[Any]):
|
|
16
|
+
"""Dump all provided args and continue code execution. This does not raise a DumpException."""
|
|
17
|
+
...
|
|
18
|
+
def get_dumps(ascending: bool = False) -> List[DumpObject]:
|
|
19
|
+
"""Get all dumps as Dump objects. If ascending is True, get dumps from oldest to most recents."""
|
|
20
|
+
...
|
|
21
|
+
def last(self) -> DumpObject:
|
|
22
|
+
"""Return last added dump."""
|
|
23
|
+
...
|
|
24
|
+
def get_serialized_dumps(ascending: bool = False) -> List[dict]:
|
|
25
|
+
"""Get all dumps as dict. If ascending is True, sort dumps from oldest to most recents."""
|
|
26
|
+
...
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Callable, List, Tuple, Any
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..authorization import AuthorizationResponse, Policy, Gate as GateObject
|
|
5
|
+
|
|
6
|
+
class Gate:
|
|
7
|
+
"""Gate facade."""
|
|
8
|
+
|
|
9
|
+
def define(permission: str, condition: Callable): ...
|
|
10
|
+
def register_policies(policies: List[Tuple[Any, Policy]]) -> "Gate": ...
|
|
11
|
+
def get_policy_for(instance_or_class: "str|Any") -> "None|Policy": ...
|
|
12
|
+
def before(before_callback: Callable): ...
|
|
13
|
+
def after(after_callback: Callable): ...
|
|
14
|
+
def allows(permission: str, *args) -> bool: ...
|
|
15
|
+
def denies(permission, *args) -> bool: ...
|
|
16
|
+
def has(permission: str) -> bool: ...
|
|
17
|
+
def for_user(user: Any) -> GateObject: ...
|
|
18
|
+
def any(permissions: List[str], *args) -> bool:
|
|
19
|
+
"""Check that every of those permissions are allowed."""
|
|
20
|
+
...
|
|
21
|
+
def none(permissions: List[str], *args) -> bool:
|
|
22
|
+
"""Check that none of those permissions are allowed."""
|
|
23
|
+
...
|
|
24
|
+
def authorize(permission: str, *args) -> bool: ...
|
|
25
|
+
def inspect(permission: str, *args) -> "bool|AuthorizationResponse":
|
|
26
|
+
"""Get permission checks results for the given user then builds and returns an
|
|
27
|
+
authorization response."""
|
|
28
|
+
...
|
|
29
|
+
def check(permission: str, *args):
|
|
30
|
+
"""The core of the authorization class. Run before() checks, permission check and then
|
|
31
|
+
after() checks."""
|
|
32
|
+
...
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
class Hash:
|
|
4
|
+
def add_driver(name: str, driver: Any): ...
|
|
5
|
+
def set_configuration(config: dict) -> "Hash": ...
|
|
6
|
+
def get_driver(name: str = None) -> Any: ...
|
|
7
|
+
def get_config_options(driver: str = None) -> dict: ...
|
|
8
|
+
def make(string: str, options: dict = {}, driver: str = None) -> str:
|
|
9
|
+
"""Hash a string and return as string based on configured hashing protocol."""
|
|
10
|
+
...
|
|
11
|
+
def make_bytes(string: str, options: dict = {}, driver: str = None) -> bytes:
|
|
12
|
+
"""Hash a string and return as bytes based on configured hashing protocol."""
|
|
13
|
+
...
|
|
14
|
+
def check(
|
|
15
|
+
self,
|
|
16
|
+
plain_string: str,
|
|
17
|
+
hashed_string: str,
|
|
18
|
+
options: dict = {},
|
|
19
|
+
driver: str = None,
|
|
20
|
+
) -> bool:
|
|
21
|
+
"""Verify that a given string matches its hashed version (based on configured hashing protocol)."""
|
|
22
|
+
...
|
|
23
|
+
def needs_rehash(
|
|
24
|
+
hashed_string: str, options: dict = {}, driver: str = None
|
|
25
|
+
) -> bool:
|
|
26
|
+
"""Verify that a given hash needs to be hashed again because parameters for generating
|
|
27
|
+
the hash have changed."""
|
|
28
|
+
...
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
class Loader:
|
|
4
|
+
def get_modules(files_or_directories: list, raise_exception: bool = False) -> dict:
|
|
5
|
+
"""Get a list of Python modules found (recursively) in the given list of files or directories.
|
|
6
|
+
If raise_exception is enabled it will raise an exception in case of error during loading a module."""
|
|
7
|
+
def find(
|
|
8
|
+
class_instance: Any,
|
|
9
|
+
paths: list,
|
|
10
|
+
class_name: str,
|
|
11
|
+
raise_exception: bool = False,
|
|
12
|
+
) -> "None|Any": ...
|
|
13
|
+
def find_all(
|
|
14
|
+
class_instance: Any, paths: list, raise_exception: bool = False
|
|
15
|
+
) -> dict: ...
|
|
16
|
+
def get_object(
|
|
17
|
+
path_or_module: "str|Any", object_name: str, raise_exception: bool = False
|
|
18
|
+
) -> Any:
|
|
19
|
+
"""Load the given object from a Python module located at path and returns a default value if
|
|
20
|
+
not found. If no object name is provided, returns the loaded module."""
|
|
21
|
+
...
|
|
22
|
+
def get_objects(
|
|
23
|
+
path_or_module: "str|Any",
|
|
24
|
+
filter_method: callable = None,
|
|
25
|
+
raise_exception: bool = False,
|
|
26
|
+
) -> dict:
|
|
27
|
+
"""Returns a dictionary of objects from the given path (file or dotted). The dictionary can
|
|
28
|
+
be filtered if a given callable is given."""
|
|
29
|
+
...
|
|
30
|
+
def get_parameters(module_or_path: "str|Any") -> dict: ...
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Any, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..mail import Mailable
|
|
5
|
+
|
|
6
|
+
class Mail:
|
|
7
|
+
"""Mail facade."""
|
|
8
|
+
|
|
9
|
+
def add_driver(name: str, driver: Any): ...
|
|
10
|
+
def set_configuration(config: dict) -> "Mail": ...
|
|
11
|
+
def get_driver(name: str = None) -> Any: ...
|
|
12
|
+
def get_config_options(driver: str = None) -> dict: ...
|
|
13
|
+
def mailable(mailable: "Mailable") -> "Mail": ...
|
|
14
|
+
def send(driver: str = None): ...
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from typing import Any, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..notification import Notification as NotificationObject
|
|
5
|
+
|
|
6
|
+
class Notification:
|
|
7
|
+
"""Notification handler facade, which handle sending/queuing notifications anonymously
|
|
8
|
+
or to notifiables through different channels."""
|
|
9
|
+
|
|
10
|
+
def add_driver(name: str, driver: str): ...
|
|
11
|
+
def get_driver(name: str) -> Any: ...
|
|
12
|
+
def set_configuration(config: dict) -> "Notification": ...
|
|
13
|
+
def get_config_options(driver: str) -> dict: ...
|
|
14
|
+
def send(
|
|
15
|
+
notifiables: list,
|
|
16
|
+
notification: "NotificationObject",
|
|
17
|
+
drivers: list = [],
|
|
18
|
+
dry: bool = False,
|
|
19
|
+
fail_silently: bool = False,
|
|
20
|
+
) -> Any:
|
|
21
|
+
"""Send the given notification to the given notifiables."""
|
|
22
|
+
...
|
|
23
|
+
def route(driver: str, route: str) -> Any:
|
|
24
|
+
"""Specify how to send a notification to an anonymous notifiable."""
|
|
25
|
+
...
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
class Queue:
|
|
4
|
+
def add_driver(name: str, driver: str): ...
|
|
5
|
+
def get_driver(name: str) -> Any: ...
|
|
6
|
+
def set_configuration(config: dict) -> "Queue": ...
|
|
7
|
+
def get_config_options(driver: str) -> dict: ...
|
|
8
|
+
def push(*jobs, **options) -> None: ...
|
|
9
|
+
def consume(options: dict) -> Any: ...
|
|
10
|
+
def retry(options: dict) -> Any: ...
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import Any, Callable, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..rates.limiters import Limiter
|
|
5
|
+
|
|
6
|
+
class RateLimiter:
|
|
7
|
+
"""Rate Limiter facades to add rate limiting to your functions."""
|
|
8
|
+
|
|
9
|
+
def register(self, name, callback: "Limiter") -> "RateLimiter":
|
|
10
|
+
"""Register a new rate limiter with the given name"""
|
|
11
|
+
...
|
|
12
|
+
def attempts(self, key: str) -> int:
|
|
13
|
+
"""Get number of attempts left for a given rate limiter key."""
|
|
14
|
+
...
|
|
15
|
+
def get_limiter(self, name: str) -> "Limiter":
|
|
16
|
+
"""Get rate limiter registered with the given name."""
|
|
17
|
+
...
|
|
18
|
+
def attempt(
|
|
19
|
+
key: str, callback: Callable, max_attempts: int, delay: int = 60
|
|
20
|
+
) -> Any:
|
|
21
|
+
"""Try to execute the given callback if not limited by the 'key' rate limiter."""
|
|
22
|
+
...
|
|
23
|
+
def too_many_attempts(self, key: str, max_attempts: int) -> bool:
|
|
24
|
+
"""Check if given rate limiter key got more (or equal) attempts than max_attempts."""
|
|
25
|
+
...
|
|
26
|
+
def hit(self, key: str, delay: int) -> int:
|
|
27
|
+
"""Add one attempt for the given key."""
|
|
28
|
+
...
|
|
29
|
+
def reset_attempts(self, key: str) -> bool:
|
|
30
|
+
"""Reset attempts count to 0 for the given key."""
|
|
31
|
+
...
|
|
32
|
+
def clear(self, key: str):
|
|
33
|
+
"""Clear all data of the given rate limiter key."""
|
|
34
|
+
...
|
|
35
|
+
def available_at(self, key: str) -> int:
|
|
36
|
+
"""Get UNIX integer timestamp at which rate limiter key will be available again."""
|
|
37
|
+
...
|
|
38
|
+
def available_in(self, key: str) -> int:
|
|
39
|
+
"""Get seconds in which rate limiter key will be available again."""
|
|
40
|
+
...
|
|
41
|
+
def remaining(self, key: str, max_attempts: int) -> int:
|
|
42
|
+
"""Get remaining attempts before given rate limiter key is limited regarding max_attempts limit."""
|
|
43
|
+
...
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, List, Any
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..routes import Route
|
|
5
|
+
|
|
6
|
+
class Request:
|
|
7
|
+
"""Request facade."""
|
|
8
|
+
|
|
9
|
+
def load():
|
|
10
|
+
"""Load request from environment."""
|
|
11
|
+
...
|
|
12
|
+
def load_params(params: dict = None):
|
|
13
|
+
"""Load request parameters."""
|
|
14
|
+
...
|
|
15
|
+
def param(param: str, default: str = "") -> str:
|
|
16
|
+
"""Get query string parameter from request."""
|
|
17
|
+
...
|
|
18
|
+
def get_route() -> "Route":
|
|
19
|
+
"""Get Route associated to request if any."""
|
|
20
|
+
...
|
|
21
|
+
def get_path() -> str:
|
|
22
|
+
"""Get request path (read from PATH_INFO) environment variable without eventual query
|
|
23
|
+
string parameters."""
|
|
24
|
+
...
|
|
25
|
+
def get_path_with_query() -> str:
|
|
26
|
+
"""Get request path (read from PATH_INFO) environment variable with eventual query
|
|
27
|
+
string parameters."""
|
|
28
|
+
...
|
|
29
|
+
def get_back_path() -> str:
|
|
30
|
+
"""Get previous request path if it has been defined as '__back' input."""
|
|
31
|
+
...
|
|
32
|
+
def get_request_method() -> str:
|
|
33
|
+
"""Get request method (read from REQUEST_METHOD environment variable)."""
|
|
34
|
+
...
|
|
35
|
+
def input(name: str, default: str = "") -> str:
|
|
36
|
+
"""Get a specific request input value with the given name. If the value does not exist in
|
|
37
|
+
the request return the default value."""
|
|
38
|
+
...
|
|
39
|
+
def cookie(name: str, value: str = None, **options) -> None:
|
|
40
|
+
"""If no value provided, read the cookie value with the given name from the request. Else
|
|
41
|
+
create a cookie in the request with the given name and value.
|
|
42
|
+
Some options can be passed when creating cookie, refer to CookieJar class."""
|
|
43
|
+
...
|
|
44
|
+
def delete_cookie(name: str) -> "Request":
|
|
45
|
+
"""Delete cookie with the given name from the request."""
|
|
46
|
+
...
|
|
47
|
+
def header(name: str, value: str = None) -> "str|None":
|
|
48
|
+
"""If no value provided, read the header value with the given name from the request. Else
|
|
49
|
+
add a header in the request with the given name and value."""
|
|
50
|
+
...
|
|
51
|
+
def all() -> dict:
|
|
52
|
+
"""Get all inputs from the request as a dictionary."""
|
|
53
|
+
...
|
|
54
|
+
def only(*inputs: List[str]) -> dict:
|
|
55
|
+
"""Get only the given inputs from the request as a dictionary."""
|
|
56
|
+
...
|
|
57
|
+
def old(key: str):
|
|
58
|
+
"""Get value from session for the given key."""
|
|
59
|
+
...
|
|
60
|
+
def is_not_safe() -> bool:
|
|
61
|
+
"""Check if the current request is considered 'safe', meaning that the request method is
|
|
62
|
+
GET, OPTIONS or HEAD."""
|
|
63
|
+
...
|
|
64
|
+
def user() -> "None|Any":
|
|
65
|
+
"""Get the current authenticated user if any. LoadUserMiddleware needs to be used for user
|
|
66
|
+
to be populated in request."""
|
|
67
|
+
...
|
|
68
|
+
def set_user(user: Any) -> "Request":
|
|
69
|
+
"""Set the current authenticated user of the request."""
|
|
70
|
+
...
|
|
71
|
+
def remove_user() -> "Request":
|
|
72
|
+
"""Log out user of the current request."""
|
|
73
|
+
...
|
|
74
|
+
def contains(route: str) -> bool:
|
|
75
|
+
"""Check if current request path match the given URL."""
|
|
76
|
+
...
|
|
77
|
+
def get_subdomain(exclude_www: bool = True) -> "None|str":
|
|
78
|
+
"""Get the request subdomain if subdomains are enabled."""
|
|
79
|
+
...
|
|
80
|
+
def get_host() -> str:
|
|
81
|
+
"""Get the request host (from HTTP_HOST environment variable)."""
|
|
82
|
+
...
|
|
83
|
+
def activate_subdomains():
|
|
84
|
+
"""Enable subdomains for this request."""
|
|
85
|
+
...
|
|
86
|
+
def is_ajax() -> bool:
|
|
87
|
+
"""Check if the current request is an AJAX request."""
|
|
88
|
+
...
|