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,68 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
class Response:
|
|
4
|
+
"""Response facade."""
|
|
5
|
+
|
|
6
|
+
def json(payload: Any, status: int = 200) -> bytes:
|
|
7
|
+
"""Set the response as a JSON response."""
|
|
8
|
+
...
|
|
9
|
+
def make_headers(content_type: str = "text/html; charset=utf-8") -> None:
|
|
10
|
+
"""Recompute Content-Length of the response after modyifing it."""
|
|
11
|
+
...
|
|
12
|
+
def header(name: str, value: str = None) -> "None|str":
|
|
13
|
+
"""Get response header for the given name if no value provided or add headers to response."""
|
|
14
|
+
...
|
|
15
|
+
def get_headers(self) -> list:
|
|
16
|
+
"""Get all response headers."""
|
|
17
|
+
...
|
|
18
|
+
def cookie(name: str, value: str = None, **options) -> "None|str":
|
|
19
|
+
"""Get response cookie for the given name if no value provided or add cookie to
|
|
20
|
+
the response with the given name, value and options."""
|
|
21
|
+
...
|
|
22
|
+
def delete_cookie(name: str) -> "Response":
|
|
23
|
+
"""Delete the cookie with the given name from the response."""
|
|
24
|
+
...
|
|
25
|
+
def get_response_content(self) -> bytes:
|
|
26
|
+
"""Get response content."""
|
|
27
|
+
...
|
|
28
|
+
def status(status: "str|int") -> "Response":
|
|
29
|
+
"""Set HTTP status code of the response."""
|
|
30
|
+
...
|
|
31
|
+
def is_status(code: int) -> bool:
|
|
32
|
+
"""Check if response has the given status code."""
|
|
33
|
+
...
|
|
34
|
+
def get_status_code(self) -> str:
|
|
35
|
+
"""Gets the HTTP status code of the response as a human string, like "200 OK"."""
|
|
36
|
+
...
|
|
37
|
+
def get_status(self): ...
|
|
38
|
+
def data(self) -> bytes:
|
|
39
|
+
"""Get the response content as bytes."""
|
|
40
|
+
...
|
|
41
|
+
def converted_data(self) -> "str|bytes":
|
|
42
|
+
"""Get the response content as string or bytes so that the WSGI server handles it."""
|
|
43
|
+
...
|
|
44
|
+
def view(view: Any, status: int = 200) -> "bytes|Response":
|
|
45
|
+
"""Set the response as a string or view."""
|
|
46
|
+
...
|
|
47
|
+
def back(self) -> "Response":
|
|
48
|
+
"""Set the response as a redirect response back to previous path defined from the
|
|
49
|
+
request."""
|
|
50
|
+
...
|
|
51
|
+
def redirect(
|
|
52
|
+
location: str = None,
|
|
53
|
+
name: str = None,
|
|
54
|
+
params: dict = {},
|
|
55
|
+
url: str = None,
|
|
56
|
+
status: int = 302,
|
|
57
|
+
) -> "Response":
|
|
58
|
+
"""Set the response as a redirect response. The redirection location can be defined
|
|
59
|
+
with the location URL or with a route name. If a route name is used, route params can
|
|
60
|
+
be provided."""
|
|
61
|
+
|
|
62
|
+
...
|
|
63
|
+
def to_bytes(self) -> "bytes":
|
|
64
|
+
"""Converts the response to bytes."""
|
|
65
|
+
...
|
|
66
|
+
def download(name: str, location: str, force: bool = False) -> "Response":
|
|
67
|
+
"""Set the response as a file download response."""
|
|
68
|
+
...
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
class Session:
|
|
4
|
+
"""Session facade."""
|
|
5
|
+
|
|
6
|
+
def add_driver(name: str, driver: Any) -> None:
|
|
7
|
+
"""Register a new session driver with the given name."""
|
|
8
|
+
...
|
|
9
|
+
def driver(driver: str) -> Any:
|
|
10
|
+
"""Get a registered session driver with the given name."""
|
|
11
|
+
...
|
|
12
|
+
def set_configuration(config: dict) -> "Session":
|
|
13
|
+
"""Set session driver options."""
|
|
14
|
+
...
|
|
15
|
+
def get_driver(name: str = None) -> Any:
|
|
16
|
+
"""Get the default session driver or the driver with the given name."""
|
|
17
|
+
...
|
|
18
|
+
def get_config_options(driver: str = None) -> dict:
|
|
19
|
+
"""Get the options of the default session driver or of the driver with the given name."""
|
|
20
|
+
...
|
|
21
|
+
def start(driver: str = None) -> "Session":
|
|
22
|
+
"""Initialize session."""
|
|
23
|
+
...
|
|
24
|
+
def get_data(self) -> dict:
|
|
25
|
+
"""Get all session data."""
|
|
26
|
+
...
|
|
27
|
+
def save(driver: str = None) -> None:
|
|
28
|
+
"""Save session data for the default session driver or the given named driver."""
|
|
29
|
+
...
|
|
30
|
+
def set(key: str, value: Any) -> None:
|
|
31
|
+
"""Save value in default session."""
|
|
32
|
+
...
|
|
33
|
+
def increment(key: str, count: int = 1) -> None:
|
|
34
|
+
"""Increment session key with given count."""
|
|
35
|
+
...
|
|
36
|
+
def decrement(key: str, count: int = 1) -> None:
|
|
37
|
+
"""Decrement session key with given count."""
|
|
38
|
+
...
|
|
39
|
+
def has(key: str) -> bool:
|
|
40
|
+
"""Check if key is present in default session."""
|
|
41
|
+
...
|
|
42
|
+
def get(key: str) -> Any:
|
|
43
|
+
"""Get value of the given key in default session."""
|
|
44
|
+
...
|
|
45
|
+
def pull(key: str) -> Any:
|
|
46
|
+
"""Get and remove value for the given key in session."""
|
|
47
|
+
...
|
|
48
|
+
def flush(self) -> None:
|
|
49
|
+
"""Delete all keys from session."""
|
|
50
|
+
...
|
|
51
|
+
def delete(key: str) -> "None|Any":
|
|
52
|
+
"""Delete the given key from session."""
|
|
53
|
+
...
|
|
54
|
+
def flash(key: str, value: Any) -> None:
|
|
55
|
+
"""Save temporary value into session."""
|
|
56
|
+
...
|
|
57
|
+
def all(self) -> dict:
|
|
58
|
+
"""Get all session data."""
|
|
59
|
+
...
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
class Storage:
|
|
4
|
+
"""File storage facade."""
|
|
5
|
+
|
|
6
|
+
def add_driver(name: str, driver: str): ...
|
|
7
|
+
def set_configuration(config: dict) -> "Storage": ...
|
|
8
|
+
def get_driver(name: str = None) -> Any: ...
|
|
9
|
+
def get_config_options(name: str = None) -> dict: ...
|
|
10
|
+
def disk(name: str = "default") -> Any:
|
|
11
|
+
"""Get the file manager instance for the given disk name."""
|
|
12
|
+
...
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class Url:
|
|
2
|
+
"""URL helper facade."""
|
|
3
|
+
|
|
4
|
+
def url(path: str = "") -> str:
|
|
5
|
+
"""Generates a fully qualified url to the given path. If no path is given this will return
|
|
6
|
+
the base url domain."""
|
|
7
|
+
...
|
|
8
|
+
def asset(alias: str, filename: str) -> str:
|
|
9
|
+
"""Generates a fully qualified URL for the given asset using the given disk
|
|
10
|
+
Example:
|
|
11
|
+
asset("local", "avatar.jpg") (take first pat)
|
|
12
|
+
asset("s3.private", "doc.pdf") (when multiple paths are specified for the disk)
|
|
13
|
+
"""
|
|
14
|
+
...
|
|
15
|
+
def route(name: str, params: dict = {}, absolute: bool = True) -> str:
|
|
16
|
+
"""Generates a fully qualified URL to the given route name.
|
|
17
|
+
Example:
|
|
18
|
+
route("users.home") : http://masonite.app/dashboard/
|
|
19
|
+
route("users.profile", {"id": 1}) : http://masonite.app/users/1/profile/
|
|
20
|
+
route("users.profile", {"id": 1}, absolute=False) : /users/1/profile/
|
|
21
|
+
"""
|
|
22
|
+
...
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from typing import Callable, Any
|
|
2
|
+
from jinja2 import PackageLoader, BaseLoader
|
|
3
|
+
|
|
4
|
+
class View:
|
|
5
|
+
"""View facade."""
|
|
6
|
+
|
|
7
|
+
def render(template: str, dictionary: dict = {}) -> "View":
|
|
8
|
+
"""Render the given template name with the given context as string."""
|
|
9
|
+
...
|
|
10
|
+
def get_content(self) -> str:
|
|
11
|
+
"""Get the rendered content as string."""
|
|
12
|
+
...
|
|
13
|
+
def hydrate_from_composers(self):
|
|
14
|
+
"""Add data into the view from specified composers."""
|
|
15
|
+
...
|
|
16
|
+
def composer(composer_name: str, dictionary: dict) -> "View":
|
|
17
|
+
"""Add/Update composer with the given name and data."""
|
|
18
|
+
...
|
|
19
|
+
def share(dictionary: dict) -> "View":
|
|
20
|
+
"""Share data to all templates."""
|
|
21
|
+
...
|
|
22
|
+
def exists(template: str) -> bool:
|
|
23
|
+
"""Check if a template with the given name exists."""
|
|
24
|
+
...
|
|
25
|
+
def add_location(template_location: str, loader: "BaseLoader" = PackageLoader):
|
|
26
|
+
"""Add location directory from which view templates can be loaded. The Jinja2 loader type
|
|
27
|
+
can be specified."""
|
|
28
|
+
...
|
|
29
|
+
def add_namespaced_location(namespace: str, template_location: str):
|
|
30
|
+
"""Add namespaced location directory from which view templates can be loaded."""
|
|
31
|
+
...
|
|
32
|
+
def add_from_package(package_name: str, path_in_package: str): ...
|
|
33
|
+
def filter(name: str, function: Callable):
|
|
34
|
+
"""Add filter functions to views with the given name."""
|
|
35
|
+
...
|
|
36
|
+
def add_extension(extension: str) -> "View":
|
|
37
|
+
"""Register Jinja2 extension to views."""
|
|
38
|
+
...
|
|
39
|
+
def load_template(template: str):
|
|
40
|
+
"""Private method for loading all the locations into the current environment."""
|
|
41
|
+
...
|
|
42
|
+
def get_current_loaders(self):
|
|
43
|
+
"""Get all enabled Jinja2 loaders."""
|
|
44
|
+
...
|
|
45
|
+
def set_separator(token: str) -> "View":
|
|
46
|
+
"""Change separator for view names (default is /)."""
|
|
47
|
+
...
|
|
48
|
+
def set_file_extension(extension: str) -> "View":
|
|
49
|
+
"""Change file view extension (default is .html)."""
|
|
50
|
+
...
|
|
51
|
+
def get_response(self) -> str:
|
|
52
|
+
"""Get the rendered content as string."""
|
|
53
|
+
...
|
|
54
|
+
def test(key: str, obj: Any) -> "View": ...
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .Facade import Facade
|
|
2
|
+
from .Request import Request
|
|
3
|
+
from .Response import Response
|
|
4
|
+
from .Mail import Mail
|
|
5
|
+
from .Hash import Hash
|
|
6
|
+
from .Url import Url
|
|
7
|
+
from .Session import Session
|
|
8
|
+
from .View import View
|
|
9
|
+
from .Gate import Gate
|
|
10
|
+
from .Auth import Auth
|
|
11
|
+
from .Config import Config
|
|
12
|
+
from .Loader import Loader
|
|
13
|
+
from .Notification import Notification
|
|
14
|
+
from .Storage import Storage
|
|
15
|
+
from .Dump import Dump
|
|
16
|
+
from .Queue import Queue
|
|
17
|
+
from .Cache import Cache
|
|
18
|
+
from .RateLimiter import RateLimiter
|
|
19
|
+
from .Broadcast import Broadcast
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Loader class to easily list, find or load any object in a given module, or folder."""
|
|
2
|
+
import inspect
|
|
3
|
+
import pkgutil
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from ..exceptions import LoaderNotFound
|
|
7
|
+
from ..utils.str import as_filepath
|
|
8
|
+
from ..utils.structures import load
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def parameters_filter(obj_name, obj):
|
|
12
|
+
return (
|
|
13
|
+
obj_name.isupper()
|
|
14
|
+
and not obj_name.startswith("__")
|
|
15
|
+
and not obj_name.endswith("__")
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Loader:
|
|
20
|
+
def get_modules(self, files_or_directories, raise_exception=False):
|
|
21
|
+
if not isinstance(files_or_directories, list):
|
|
22
|
+
files_or_directories = [files_or_directories]
|
|
23
|
+
|
|
24
|
+
_modules = {}
|
|
25
|
+
module_paths = list(map(as_filepath, files_or_directories))
|
|
26
|
+
for module_loader, name, _ in pkgutil.iter_modules(module_paths):
|
|
27
|
+
module = load(
|
|
28
|
+
f"{os.path.relpath(module_loader.path)}.{name}",
|
|
29
|
+
raise_exception=raise_exception,
|
|
30
|
+
)
|
|
31
|
+
_modules.update({name: module})
|
|
32
|
+
return _modules
|
|
33
|
+
|
|
34
|
+
def find(self, class_instance, paths, class_name, raise_exception=False):
|
|
35
|
+
_classes = self.find_all(class_instance, paths, raise_exception)
|
|
36
|
+
for name, obj in _classes.items():
|
|
37
|
+
if name == class_name:
|
|
38
|
+
return obj
|
|
39
|
+
if raise_exception:
|
|
40
|
+
raise LoaderNotFound(
|
|
41
|
+
f"No {class_instance} named {class_name} has been found in {paths}"
|
|
42
|
+
)
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
def find_all(self, class_instance, paths, raise_exception=False):
|
|
46
|
+
_classes = {}
|
|
47
|
+
for module in self.get_modules(paths, raise_exception).values():
|
|
48
|
+
for obj_name, obj in inspect.getmembers(module):
|
|
49
|
+
# check if obj is the same class as the given one
|
|
50
|
+
if inspect.isclass(obj) and issubclass(obj, class_instance):
|
|
51
|
+
# check if the class really belongs to those paths to load internal only
|
|
52
|
+
if obj.__module__.startswith(module.__package__):
|
|
53
|
+
_classes.update({obj_name: obj})
|
|
54
|
+
if not len(_classes.keys()) and raise_exception:
|
|
55
|
+
raise LoaderNotFound(f"No {class_instance} have been found in {paths}")
|
|
56
|
+
return _classes
|
|
57
|
+
|
|
58
|
+
def get_object(self, path_or_module, object_name, raise_exception=False):
|
|
59
|
+
return load(path_or_module, object_name, raise_exception=raise_exception)
|
|
60
|
+
|
|
61
|
+
def get_objects(self, path_or_module, filter_method=None, raise_exception=False):
|
|
62
|
+
"""Returns a dictionary of objects from the given path (file or dotted). The dictionary can
|
|
63
|
+
be filtered if a given callable is given."""
|
|
64
|
+
if isinstance(path_or_module, str):
|
|
65
|
+
module = load(path_or_module, raise_exception=raise_exception)
|
|
66
|
+
else:
|
|
67
|
+
module = path_or_module
|
|
68
|
+
if not module:
|
|
69
|
+
return None
|
|
70
|
+
return dict(inspect.getmembers(module, filter_method))
|
|
71
|
+
|
|
72
|
+
def get_parameters(self, module_or_path):
|
|
73
|
+
_parameters = {}
|
|
74
|
+
for name, obj in self.get_objects(module_or_path).items():
|
|
75
|
+
if parameters_filter(name, obj):
|
|
76
|
+
_parameters.update({name: obj})
|
|
77
|
+
|
|
78
|
+
return _parameters
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .Loader import Loader
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .Provider import Provider
|
|
2
|
+
from ..configuration import Configuration
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
class ConfigurationProvider(Provider):
|
|
6
|
+
def register(self):
|
|
7
|
+
self.application.bind('config.location', os.path.join(self.application.base_path, "config"))
|
|
8
|
+
configuration = Configuration(self.application)
|
|
9
|
+
configuration.load()
|
|
10
|
+
self.application.bind("config", configuration)
|
|
11
|
+
|
|
12
|
+
def boot(self):
|
|
13
|
+
pass
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from ..container import Container
|
|
5
|
+
|
|
6
|
+
class Provider:
|
|
7
|
+
def __init__(self, application) -> None:
|
|
8
|
+
self.application = application
|
|
9
|
+
|
|
10
|
+
def register(self) -> None:
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
def boot(self) -> None:
|
|
14
|
+
pass
|
|
File without changes
|