fastapi-factory-utilities 0.1.0__py3-none-any.whl → 0.2.1__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.
Potentially problematic release.
This version of fastapi-factory-utilities might be problematic. Click here for more details.
- fastapi_factory_utilities/core/api/v1/sys/health.py +56 -12
- fastapi_factory_utilities/core/api/v1/sys/readiness.py +19 -12
- fastapi_factory_utilities/core/app/__init__.py +7 -12
- fastapi_factory_utilities/core/app/application.py +133 -0
- fastapi_factory_utilities/core/app/builder.py +123 -0
- fastapi_factory_utilities/core/app/config.py +164 -0
- fastapi_factory_utilities/core/app/exceptions.py +20 -0
- fastapi_factory_utilities/core/app/fastapi_builder.py +85 -0
- fastapi_factory_utilities/core/app/plugin_manager/__init__.py +15 -0
- fastapi_factory_utilities/core/app/plugin_manager/exceptions.py +33 -0
- fastapi_factory_utilities/core/app/plugin_manager/plugin_manager.py +190 -0
- fastapi_factory_utilities/core/exceptions.py +43 -0
- fastapi_factory_utilities/core/plugins/__init__.py +21 -0
- fastapi_factory_utilities/core/plugins/example/__init__.py +31 -0
- fastapi_factory_utilities/core/plugins/httpx_plugin/__init__.py +31 -0
- fastapi_factory_utilities/core/plugins/odm_plugin/__init__.py +74 -17
- fastapi_factory_utilities/core/plugins/odm_plugin/builder.py +27 -35
- fastapi_factory_utilities/core/plugins/odm_plugin/configs.py +1 -3
- fastapi_factory_utilities/core/plugins/odm_plugin/depends.py +30 -0
- fastapi_factory_utilities/core/plugins/opentelemetry_plugin/__init__.py +5 -5
- fastapi_factory_utilities/core/plugins/opentelemetry_plugin/builder.py +7 -7
- fastapi_factory_utilities/core/protocols.py +19 -16
- fastapi_factory_utilities/core/services/status/__init__.py +14 -0
- fastapi_factory_utilities/core/services/status/enums.py +30 -0
- fastapi_factory_utilities/core/services/status/exceptions.py +27 -0
- fastapi_factory_utilities/core/services/status/health_calculator_strategies.py +48 -0
- fastapi_factory_utilities/core/services/status/readiness_calculator_strategies.py +41 -0
- fastapi_factory_utilities/core/services/status/services.py +218 -0
- fastapi_factory_utilities/core/services/status/types.py +128 -0
- fastapi_factory_utilities/core/utils/configs.py +1 -1
- fastapi_factory_utilities/core/utils/status.py +71 -0
- fastapi_factory_utilities/core/utils/uvicorn.py +7 -8
- fastapi_factory_utilities/example/__init__.py +3 -3
- fastapi_factory_utilities/example/api/books/routes.py +7 -10
- fastapi_factory_utilities/example/app.py +50 -0
- fastapi_factory_utilities/example/application.yaml +5 -9
- fastapi_factory_utilities/example/services/books/__init__.py +2 -2
- fastapi_factory_utilities/example/services/books/services.py +9 -0
- fastapi_factory_utilities/py.typed +0 -0
- {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.1.dist-info}/METADATA +6 -4
- fastapi_factory_utilities-0.2.1.dist-info/RECORD +71 -0
- {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.1.dist-info}/WHEEL +1 -1
- fastapi_factory_utilities/core/app/base/__init__.py +0 -17
- fastapi_factory_utilities/core/app/base/application.py +0 -123
- fastapi_factory_utilities/core/app/base/config_abstract.py +0 -78
- fastapi_factory_utilities/core/app/base/exceptions.py +0 -25
- fastapi_factory_utilities/core/app/base/fastapi_application_abstract.py +0 -88
- fastapi_factory_utilities/core/app/base/plugins_manager_abstract.py +0 -136
- fastapi_factory_utilities/example/app/__init__.py +0 -6
- fastapi_factory_utilities/example/app/app.py +0 -37
- fastapi_factory_utilities/example/app/config.py +0 -12
- fastapi_factory_utilities-0.1.0.dist-info/RECORD +0 -58
- {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.1.dist-info}/LICENSE +0 -0
- {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
fastapi_factory_utilities/__main__.py,sha256=w8o9KpyHcxGyLHmTK8ixbIqJIsB3NbIGuAMY7OfnxrA,147
|
|
2
|
+
fastapi_factory_utilities/core/__init__.py,sha256=tt5a-MgeFt_oACkc9K5xl2rynIbca9DGqsKBDEqGzto,34
|
|
3
|
+
fastapi_factory_utilities/core/api/__init__.py,sha256=eehUFVDPk07MUPIorGdC8WqDRB8NjdSy7Za55CdLrps,542
|
|
4
|
+
fastapi_factory_utilities/core/api/tags.py,sha256=3hQcTeW0FS78sPTJ2PB44dMDTSkoW-xKj7rrfKX2Lk0,154
|
|
5
|
+
fastapi_factory_utilities/core/api/v1/sys/__init__.py,sha256=mTXhpn3_KgQ1snt0-0PFmGvFr4n5srQRRADEdRSGFJM,345
|
|
6
|
+
fastapi_factory_utilities/core/api/v1/sys/health.py,sha256=IF51Z1seOFn91m3FC57U8uWfAA7c_EhhBpjbu_ly9WQ,2807
|
|
7
|
+
fastapi_factory_utilities/core/api/v1/sys/readiness.py,sha256=xIY8pQLShU7KWRtlOUK5gTDyZ8aB1KBvLczC6boT-tg,1711
|
|
8
|
+
fastapi_factory_utilities/core/app/__init__.py,sha256=I04abOkkWiY9ChgkUNeiwnuWq8kkBoRAtMLBUKB7J7Y,405
|
|
9
|
+
fastapi_factory_utilities/core/app/application.py,sha256=XdfQRG8IwyukEYXNF6i2s3qq0eAo1_XG9Xa9yV7zKf8,4975
|
|
10
|
+
fastapi_factory_utilities/core/app/builder.py,sha256=aPmtnGPAsCF4vGIlqSLKWW5XW7JF3nBN7bfk_zudR28,4374
|
|
11
|
+
fastapi_factory_utilities/core/app/config.py,sha256=7ELIoCy1AGCD4Zq7O-jZk6VJcqDU8H-00CSrvtwzdZE,6466
|
|
12
|
+
fastapi_factory_utilities/core/app/enums.py,sha256=X1upnaehYU0eHExXTde5xsH-pI9q7HZDNsOEF5PApdg,226
|
|
13
|
+
fastapi_factory_utilities/core/app/exceptions.py,sha256=tQDf0_4j5xgCbku7TL7JaZGs3_bjsWG2YLBCydQJpPw,664
|
|
14
|
+
fastapi_factory_utilities/core/app/fastapi_builder.py,sha256=DgIqiCnJK6cqsG-sg4H7Pi0lkhaxOhSLQt_ksHjpjW0,2835
|
|
15
|
+
fastapi_factory_utilities/core/app/plugin_manager/__init__.py,sha256=eMfxCsk41Caw_juAawmDZHhytNI_ubXmqfRDug2AzvQ,319
|
|
16
|
+
fastapi_factory_utilities/core/app/plugin_manager/exceptions.py,sha256=CFrZvROT7mLzNpXWwDra1j08lA_7ZrSrOHN94sEEfnQ,1026
|
|
17
|
+
fastapi_factory_utilities/core/app/plugin_manager/plugin_manager.py,sha256=5E_Qp535xNJHNujZ_QRiMfIkDUy9F_3Rbjlclny5P08,6682
|
|
18
|
+
fastapi_factory_utilities/core/exceptions.py,sha256=7ntbaMptYn5OOPeKPVR4zU98NIC0j53NQSkqVP1bD68,1362
|
|
19
|
+
fastapi_factory_utilities/core/plugins/__init__.py,sha256=W-BCkqP0xG980980z3mc8T6Vrp1Akv4szA0PRzkUbiU,756
|
|
20
|
+
fastapi_factory_utilities/core/plugins/example/__init__.py,sha256=GF69IygLXxzrCh7VryekEWun663kKBhWtRS3w-1tzBc,1030
|
|
21
|
+
fastapi_factory_utilities/core/plugins/httpx_plugin/__init__.py,sha256=P5FUyv7mQr8RZWQ8ifkoK8GXvqSI71q2b2dm-ag2JhQ,1028
|
|
22
|
+
fastapi_factory_utilities/core/plugins/odm_plugin/__init__.py,sha256=zR1WCBdoXz6RCTJm_NbjSuLTS77hGXuRz0IOAE3kZ1I,5278
|
|
23
|
+
fastapi_factory_utilities/core/plugins/odm_plugin/builder.py,sha256=xmDlyDyXzK2TU-FH4f0QlghBS9E0wvJyaboeI1PBTUE,7692
|
|
24
|
+
fastapi_factory_utilities/core/plugins/odm_plugin/configs.py,sha256=_8sE7h9AkNLSeBdGgUIyaaZqt9HCnocioX324ZNg2wA,328
|
|
25
|
+
fastapi_factory_utilities/core/plugins/odm_plugin/depends.py,sha256=OcLsfTLzMBk_xFV6qsMy_-qFkiphEbbEuaHUooagxg8,730
|
|
26
|
+
fastapi_factory_utilities/core/plugins/odm_plugin/documents.py,sha256=ENEB-Lm3T7_tN1xuIYPsUh8fpWj4aqh0xmrZt6vJCK0,1075
|
|
27
|
+
fastapi_factory_utilities/core/plugins/odm_plugin/exceptions.py,sha256=acnKJB0lGAzDs-7-LjBap8shjP3iV1a7dw7ouPVF27o,551
|
|
28
|
+
fastapi_factory_utilities/core/plugins/odm_plugin/repositories.py,sha256=Wxh5C_gnU4jY8H5qpvcFuSlaM1dLrsDXqxGuuaxwB68,6912
|
|
29
|
+
fastapi_factory_utilities/core/plugins/opentelemetry_plugin/__init__.py,sha256=UsXPjiAASn5GIHW8vrF32mklxGNq8ajILV-ty4K1Tbs,4371
|
|
30
|
+
fastapi_factory_utilities/core/plugins/opentelemetry_plugin/builder.py,sha256=DsD1vUtTIMXCxLsQ2KbMaQthdPfvZsI95uLdD7pkeiE,9838
|
|
31
|
+
fastapi_factory_utilities/core/plugins/opentelemetry_plugin/configs.py,sha256=4mMa5SrmnPY1R_gVFRtFhi9WNaTGEGZL5iNNhyjcZQ0,3448
|
|
32
|
+
fastapi_factory_utilities/core/plugins/opentelemetry_plugin/exceptions.py,sha256=CpsHayfQpP0zghN8y5PP6TBy-cXhHoNxBR--I86gAdE,327
|
|
33
|
+
fastapi_factory_utilities/core/plugins/opentelemetry_plugin/helpers.py,sha256=qpTIzX67orJz7vy6SBIwRs24omMBoToJkhpurZRjPuk,1533
|
|
34
|
+
fastapi_factory_utilities/core/protocols.py,sha256=TzZKr_KfmTphk2LL-TD2XzxNlLbihbGM2DxWMhc5lEQ,2428
|
|
35
|
+
fastapi_factory_utilities/core/services/status/__init__.py,sha256=N5H0cCN9ZFu_0YZar4RLdCDEjKMICrIhNtfKgB0LI78,370
|
|
36
|
+
fastapi_factory_utilities/core/services/status/enums.py,sha256=IUxWAd0Ecknri4BqzaqoDRRhT_8LdcgtQcNqgNVDXGE,599
|
|
37
|
+
fastapi_factory_utilities/core/services/status/exceptions.py,sha256=_fQFGqHKnG54Hs-ZtC4gs0xwzSH246_WwQOonraoGKw,856
|
|
38
|
+
fastapi_factory_utilities/core/services/status/health_calculator_strategies.py,sha256=p2KKJo-dq1j9iWHT0mvlBKtldH9m8l31aytLkUsb9nQ,1634
|
|
39
|
+
fastapi_factory_utilities/core/services/status/readiness_calculator_strategies.py,sha256=hA1LX2pSxva-7bVaQ0dw8NpTbl1ZWDtXd9xzqQUGUsI,1354
|
|
40
|
+
fastapi_factory_utilities/core/services/status/services.py,sha256=qtgYdnxNQMbb6q6G9uGasRO3lZcpiWNmw1padPkh6jA,8490
|
|
41
|
+
fastapi_factory_utilities/core/services/status/types.py,sha256=GJOGRra6NtpUS4q1cr4cdWR0BbIUtEwP7vQX-sXX5jQ,3297
|
|
42
|
+
fastapi_factory_utilities/core/utils/configs.py,sha256=qM0pCrsK8ZyfCoyova_VrhR4eUX3LSPCbWunGMWcSVg,2581
|
|
43
|
+
fastapi_factory_utilities/core/utils/importlib.py,sha256=DYcPo7K0s95WV5xxtucpufWsTj8Pxv25sWunDmmNUYI,797
|
|
44
|
+
fastapi_factory_utilities/core/utils/log.py,sha256=6V9CL3bQio4e47YxcSXM2JQRGhVxuBfmcEbcF4RtCfQ,6393
|
|
45
|
+
fastapi_factory_utilities/core/utils/status.py,sha256=1zxur98Wfum3JzpuzoAPoRIwQmXhFsTS2oxgbn5uFfg,1933
|
|
46
|
+
fastapi_factory_utilities/core/utils/uvicorn.py,sha256=JJ_HNjpJz1IDQz3a4hPcxpf5_nhGypDUSdoZA7HkCvU,1335
|
|
47
|
+
fastapi_factory_utilities/core/utils/yaml_reader.py,sha256=G7F1SFynghUYjuTZTNotNW9OIiCaeGAWkcYvTFYsCMQ,6101
|
|
48
|
+
fastapi_factory_utilities/example/__init__.py,sha256=LEKnPTBcgDyfHeOjlVxjK5lFdFqS-7-mHDuVuM2Jh_Y,206
|
|
49
|
+
fastapi_factory_utilities/example/__main__.py,sha256=Iwp_6rK7Lcv2F-XAKn6xjxQHOWjx2OjgwKAr91tfUfk,135
|
|
50
|
+
fastapi_factory_utilities/example/api/__init__.py,sha256=qI82eeSwVjR6jSkX1pxm8ALv9WPQ_iHurFY4G2K7VzE,554
|
|
51
|
+
fastapi_factory_utilities/example/api/books/__init__.py,sha256=zXARBnjywJwg1XsLbcixYWcHH4uC9mF-kbbX4P8cVgA,160
|
|
52
|
+
fastapi_factory_utilities/example/api/books/responses.py,sha256=21WeD6bdg0MCD_0vRHwmsL4W79iDcG9NnDLemXysc84,540
|
|
53
|
+
fastapi_factory_utilities/example/api/books/routes.py,sha256=bwg8Bhvoj9vx2SdwunzFS-Z3cHECtjl_yGdo8MfiGEM,1529
|
|
54
|
+
fastapi_factory_utilities/example/app.py,sha256=mcXQOg0A74mc8xFT0XuRHne3YjXXI7dTMV48G_Ypng8,1555
|
|
55
|
+
fastapi_factory_utilities/example/application.yaml,sha256=5xRyFSuMxmgZ5Mikai94UqKYJ7PxJp8omlXobTjv14M,485
|
|
56
|
+
fastapi_factory_utilities/example/entities/books/__init__.py,sha256=q2UTwLyCs3te38n7RgwT0go3Hp0bE9-NvoX7P-DR-3o,185
|
|
57
|
+
fastapi_factory_utilities/example/entities/books/entities.py,sha256=rLE01lE7U6WizrD5ZHMRwkynd8_dWF6DltBFH61f-Do,405
|
|
58
|
+
fastapi_factory_utilities/example/entities/books/enums.py,sha256=lXYUvhIkT1pi0teflMpnqeafeiBZMokyWxoFLgzV6a8,330
|
|
59
|
+
fastapi_factory_utilities/example/entities/books/types.py,sha256=7LYGPu-CcI3noIORJyIZlVF-CBugWPXEqgDzWrO3XmQ,1558
|
|
60
|
+
fastapi_factory_utilities/example/models/__init__.py,sha256=RJmp3R9bhbQv7n0WOlsHP65LqbEs_DjF9hzYKwYTRGo,22
|
|
61
|
+
fastapi_factory_utilities/example/models/books/__init__.py,sha256=1GJFCYMGZugQRxlFl-q7fPBFvNsl2ykeW8lV7rpURHU,181
|
|
62
|
+
fastapi_factory_utilities/example/models/books/document.py,sha256=lYJfMGr5GqEEsn7L--PFs75hC2q-jQx77wl7EhTrp5U,568
|
|
63
|
+
fastapi_factory_utilities/example/models/books/repository.py,sha256=7K63uAsSEGZ2EXqufU4Tc8KpymgXK8JX8WjAE2Sw8ok,387
|
|
64
|
+
fastapi_factory_utilities/example/services/books/__init__.py,sha256=Z06yNRoA7Zg3TGN-Q9rrvJg6Bbx-qJw661MVwukV6vQ,148
|
|
65
|
+
fastapi_factory_utilities/example/services/books/services.py,sha256=-x7d4hotUWLzWo5uImMjFmtNcSTHwWv2bfttIbYYKbA,5380
|
|
66
|
+
fastapi_factory_utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
|
+
fastapi_factory_utilities-0.2.1.dist-info/LICENSE,sha256=iO1nLzMMst6vEiqgSUrfrbetM7b0bvdzXhbed5tqG8o,1074
|
|
68
|
+
fastapi_factory_utilities-0.2.1.dist-info/METADATA,sha256=vmZIAlSo0KVgELzN0LWH9B3GnurywJGoCJ9_5WarIM0,3314
|
|
69
|
+
fastapi_factory_utilities-0.2.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
|
70
|
+
fastapi_factory_utilities-0.2.1.dist-info/entry_points.txt,sha256=IK0VcBexXo4uXQmTrbfhhnnfq4GmXPRn0GBB8hzlsq4,101
|
|
71
|
+
fastapi_factory_utilities-0.2.1.dist-info/RECORD,,
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"""Package for the base application, abstract config classes and related exceptions."""
|
|
2
|
-
|
|
3
|
-
from .application import BaseApplication
|
|
4
|
-
from .config_abstract import AppConfigAbstract
|
|
5
|
-
from .exceptions import (
|
|
6
|
-
ApplicationConfigFactoryException,
|
|
7
|
-
ApplicationFactoryException,
|
|
8
|
-
BaseApplicationException,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
__all__: list[str] = [
|
|
12
|
-
"BaseApplication",
|
|
13
|
-
"AppConfigAbstract",
|
|
14
|
-
"ApplicationConfigFactoryException",
|
|
15
|
-
"ApplicationFactoryException",
|
|
16
|
-
"BaseApplicationException",
|
|
17
|
-
]
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
"""Provides the abstract class for the application."""
|
|
2
|
-
|
|
3
|
-
from collections.abc import AsyncGenerator
|
|
4
|
-
from contextlib import asynccontextmanager
|
|
5
|
-
from typing import ClassVar, Self, cast
|
|
6
|
-
|
|
7
|
-
import starlette.types
|
|
8
|
-
from beanie import Document
|
|
9
|
-
from fastapi import FastAPI
|
|
10
|
-
|
|
11
|
-
from fastapi_factory_utilities.core.api import api
|
|
12
|
-
from fastapi_factory_utilities.core.utils.log import LogModeEnum, setup_log
|
|
13
|
-
|
|
14
|
-
from .config_abstract import AppConfigAbstract, AppConfigBuilder
|
|
15
|
-
from .fastapi_application_abstract import FastAPIAbstract
|
|
16
|
-
from .plugins_manager_abstract import (
|
|
17
|
-
ApplicationPluginManagerAbstract,
|
|
18
|
-
PluginsActivationList,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class BaseApplication(FastAPIAbstract, ApplicationPluginManagerAbstract):
|
|
23
|
-
"""Application abstract class."""
|
|
24
|
-
|
|
25
|
-
PACKAGE_NAME: str = ""
|
|
26
|
-
|
|
27
|
-
CONFIG_CLASS: ClassVar[type[AppConfigAbstract]] = AppConfigAbstract
|
|
28
|
-
|
|
29
|
-
ODM_DOCUMENT_MODELS: ClassVar[list[type[Document]]] = []
|
|
30
|
-
|
|
31
|
-
def __init__(self, config: AppConfigAbstract, plugin_activation_list: PluginsActivationList | None = None) -> None:
|
|
32
|
-
"""Instantiate the application.
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
config (AppConfigAbstract): The application configuration.
|
|
36
|
-
plugin_activation_list (PluginsActivationList | None, optional): The plugins activation list.
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
None
|
|
40
|
-
|
|
41
|
-
Raises:
|
|
42
|
-
ValueError: If the package name is not set.
|
|
43
|
-
"""
|
|
44
|
-
if self.PACKAGE_NAME == "":
|
|
45
|
-
raise ValueError("The package name must be set in the concrete application class.")
|
|
46
|
-
|
|
47
|
-
self._config: AppConfigAbstract = config
|
|
48
|
-
FastAPIAbstract.__init__(
|
|
49
|
-
self=cast(FastAPIAbstract, self),
|
|
50
|
-
config=self._config,
|
|
51
|
-
api_router=api,
|
|
52
|
-
lifespan=cast(starlette.types.StatelessLifespan[starlette.types.ASGIApp], self.fastapi_lifespan),
|
|
53
|
-
)
|
|
54
|
-
ApplicationPluginManagerAbstract.__init__(
|
|
55
|
-
self=cast(ApplicationPluginManagerAbstract, self), plugin_activation_list=plugin_activation_list
|
|
56
|
-
)
|
|
57
|
-
self._on_load()
|
|
58
|
-
|
|
59
|
-
@classmethod
|
|
60
|
-
def main(cls) -> None:
|
|
61
|
-
"""Main function.
|
|
62
|
-
|
|
63
|
-
This must be the same for all applications.
|
|
64
|
-
"""
|
|
65
|
-
from fastapi_factory_utilities.core.utils.uvicorn import ( # pylint: disable=import-outside-toplevel
|
|
66
|
-
UvicornUtils,
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
setup_log(mode=LogModeEnum.CONSOLE)
|
|
70
|
-
application: BaseApplication = cls.build()
|
|
71
|
-
uvicorn_utils = UvicornUtils(app=application)
|
|
72
|
-
|
|
73
|
-
try:
|
|
74
|
-
uvicorn_utils.serve()
|
|
75
|
-
except KeyboardInterrupt:
|
|
76
|
-
pass
|
|
77
|
-
|
|
78
|
-
@classmethod
|
|
79
|
-
def build_config(cls) -> AppConfigAbstract:
|
|
80
|
-
"""Build the application configuration.
|
|
81
|
-
|
|
82
|
-
Returns:
|
|
83
|
-
AppConfigAbstract: The application configuration.
|
|
84
|
-
"""
|
|
85
|
-
config_builder: AppConfigBuilder = AppConfigBuilder(
|
|
86
|
-
package_name=cls.PACKAGE_NAME, config_class=cls.CONFIG_CLASS
|
|
87
|
-
)
|
|
88
|
-
return config_builder.build()
|
|
89
|
-
|
|
90
|
-
@classmethod
|
|
91
|
-
def build(
|
|
92
|
-
cls, config: AppConfigAbstract | None = None, plugin_activation_list: PluginsActivationList | None = None
|
|
93
|
-
) -> Self:
|
|
94
|
-
"""Build the application.
|
|
95
|
-
|
|
96
|
-
Args:
|
|
97
|
-
config (AppConfigAbstract | None, optional): The application configuration. Defaults to None.
|
|
98
|
-
plugin_activation_list (PluginsActivationList | None, optional): The plugins activation list.
|
|
99
|
-
Defaults to None.
|
|
100
|
-
"""
|
|
101
|
-
if config is None:
|
|
102
|
-
config = cls.build_config()
|
|
103
|
-
|
|
104
|
-
return cls(config=config, plugin_activation_list=plugin_activation_list)
|
|
105
|
-
|
|
106
|
-
@asynccontextmanager
|
|
107
|
-
async def fastapi_lifespan(self, fastapi_application: FastAPI) -> AsyncGenerator[None, None]:
|
|
108
|
-
"""Provide the lifespan context manager for FastAPI.
|
|
109
|
-
|
|
110
|
-
Args:
|
|
111
|
-
fastapi_application (FastAPI): The FastAPI application.
|
|
112
|
-
|
|
113
|
-
Returns:
|
|
114
|
-
AsyncGenerator[None]: The lifespan context manager.
|
|
115
|
-
"""
|
|
116
|
-
del fastapi_application
|
|
117
|
-
await self.plugins_on_startup()
|
|
118
|
-
yield
|
|
119
|
-
await self.plugins_on_shutdown()
|
|
120
|
-
|
|
121
|
-
def get_config(self) -> AppConfigAbstract:
|
|
122
|
-
"""Get the application configuration."""
|
|
123
|
-
return self._config
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"""Provide the configuration for the app server."""
|
|
2
|
-
|
|
3
|
-
from pydantic import Field
|
|
4
|
-
|
|
5
|
-
from fastapi_factory_utilities.core.app.base.exceptions import (
|
|
6
|
-
ApplicationConfigFactoryException,
|
|
7
|
-
)
|
|
8
|
-
from fastapi_factory_utilities.core.app.base.plugins_manager_abstract import (
|
|
9
|
-
PluginsActivationList,
|
|
10
|
-
)
|
|
11
|
-
from fastapi_factory_utilities.core.utils.configs import (
|
|
12
|
-
UnableToReadConfigFileError,
|
|
13
|
-
ValueErrorConfigError,
|
|
14
|
-
build_config_from_file_in_package,
|
|
15
|
-
)
|
|
16
|
-
from fastapi_factory_utilities.core.utils.log import LoggingConfig
|
|
17
|
-
|
|
18
|
-
from ..enums import EnvironmentEnum
|
|
19
|
-
from .fastapi_application_abstract import FastAPIConfigAbstract
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class AppConfigAbstract(FastAPIConfigAbstract, PluginsActivationList):
|
|
23
|
-
"""Application configuration abstract class."""
|
|
24
|
-
|
|
25
|
-
environment: EnvironmentEnum
|
|
26
|
-
service_name: str
|
|
27
|
-
service_namespace: str
|
|
28
|
-
|
|
29
|
-
logging: list[LoggingConfig] = Field(default_factory=list, description="Logging configuration.")
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class AppConfigBuilder:
|
|
33
|
-
"""Application configuration builder."""
|
|
34
|
-
|
|
35
|
-
DEFAULT_FILENAME: str = "application.yaml"
|
|
36
|
-
DEFAULT_YAML_BASE_KEY: str = "application"
|
|
37
|
-
|
|
38
|
-
def __init__(
|
|
39
|
-
self,
|
|
40
|
-
package_name: str,
|
|
41
|
-
config_class: type[AppConfigAbstract],
|
|
42
|
-
filename: str = DEFAULT_FILENAME,
|
|
43
|
-
yaml_base_key: str = DEFAULT_YAML_BASE_KEY,
|
|
44
|
-
) -> None:
|
|
45
|
-
"""Instantiate the builder.
|
|
46
|
-
|
|
47
|
-
Args:
|
|
48
|
-
package_name (str): The package name.
|
|
49
|
-
config_class (Type[AppConfigAbstract]): The configuration class.
|
|
50
|
-
filename (str, optional): The filename. Defaults to DEFAULT_FILENAME.
|
|
51
|
-
yaml_base_key (str, optional): The YAML base key. Defaults to DEFAULT_YAML_BASE_KEY.
|
|
52
|
-
"""
|
|
53
|
-
self.package_name: str = package_name
|
|
54
|
-
self.config_class: type[AppConfigAbstract] = config_class
|
|
55
|
-
self.filename: str = filename
|
|
56
|
-
self.yaml_base_key: str = yaml_base_key
|
|
57
|
-
|
|
58
|
-
def build(self) -> AppConfigAbstract:
|
|
59
|
-
"""Build the configuration.
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
AppConfigAbstract: The configuration.
|
|
63
|
-
"""
|
|
64
|
-
try:
|
|
65
|
-
config: AppConfigAbstract = build_config_from_file_in_package(
|
|
66
|
-
package_name=self.package_name,
|
|
67
|
-
config_class=self.config_class,
|
|
68
|
-
filename=self.filename,
|
|
69
|
-
yaml_base_key=self.yaml_base_key,
|
|
70
|
-
)
|
|
71
|
-
except UnableToReadConfigFileError as exception:
|
|
72
|
-
raise ApplicationConfigFactoryException("Unable to read the application configuration file.") from exception
|
|
73
|
-
except ValueErrorConfigError as exception:
|
|
74
|
-
raise ApplicationConfigFactoryException(
|
|
75
|
-
"Unable to create the application configuration model."
|
|
76
|
-
) from exception
|
|
77
|
-
|
|
78
|
-
return config
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"""Provides the exceptions for the application factory."""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class BaseApplicationException(BaseException):
|
|
5
|
-
"""Base application exception."""
|
|
6
|
-
|
|
7
|
-
pass
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class ApplicationFactoryException(BaseApplicationException):
|
|
11
|
-
"""Application factory exception."""
|
|
12
|
-
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class ApplicationConfigFactoryException(BaseApplicationException):
|
|
17
|
-
"""Application configuration factory exception."""
|
|
18
|
-
|
|
19
|
-
pass
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class ApplicationPluginManagerException(BaseApplicationException):
|
|
23
|
-
"""Application plugin manager exception."""
|
|
24
|
-
|
|
25
|
-
pass
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"""Provides an abstract class for FastAPI application integration."""
|
|
2
|
-
|
|
3
|
-
from abc import ABC
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
import starlette.types
|
|
7
|
-
from fastapi import APIRouter, FastAPI
|
|
8
|
-
from fastapi.middleware.cors import CORSMiddleware
|
|
9
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class FastAPIConfigAbstract(ABC, BaseModel):
|
|
13
|
-
"""Partial configuration for FastAPI."""
|
|
14
|
-
|
|
15
|
-
model_config = ConfigDict(strict=False)
|
|
16
|
-
|
|
17
|
-
# Application metadata
|
|
18
|
-
title: str
|
|
19
|
-
description: str
|
|
20
|
-
version: str
|
|
21
|
-
|
|
22
|
-
# Host configuration
|
|
23
|
-
host: str = Field(default="0.0.0.0")
|
|
24
|
-
port: int = Field(default=8000)
|
|
25
|
-
|
|
26
|
-
# Root configuration
|
|
27
|
-
root_path: str = Field(default="")
|
|
28
|
-
|
|
29
|
-
# Debug mode
|
|
30
|
-
debug: bool = Field(default=False, strict=False)
|
|
31
|
-
|
|
32
|
-
# Uvicorn configuration
|
|
33
|
-
reload: bool = Field(default=False, strict=False)
|
|
34
|
-
workers: int = Field(default=1, strict=False)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class FastAPIAbstract(ABC):
|
|
38
|
-
"""Application integration with FastAPI.
|
|
39
|
-
|
|
40
|
-
TODO: Replace by a Factory pattern.
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
def __init__(
|
|
44
|
-
self,
|
|
45
|
-
config: FastAPIConfigAbstract,
|
|
46
|
-
api_router: APIRouter | None = None,
|
|
47
|
-
lifespan: starlette.types.StatelessLifespan[starlette.types.ASGIApp] | None = None,
|
|
48
|
-
) -> None:
|
|
49
|
-
"""Instanciate the FastAPI application.
|
|
50
|
-
|
|
51
|
-
Args:
|
|
52
|
-
config (FastAPIConfigAbstract): The FastAPI configuration.
|
|
53
|
-
api_router (APIRouter, optional): The API router to include.
|
|
54
|
-
Defaults to None.
|
|
55
|
-
lifespan (AsyncGenerator[None, None], optional): The lifespan
|
|
56
|
-
|
|
57
|
-
Returns:
|
|
58
|
-
None
|
|
59
|
-
|
|
60
|
-
"""
|
|
61
|
-
self._fastapi_app: FastAPI = FastAPI(
|
|
62
|
-
title=config.title,
|
|
63
|
-
description=config.description,
|
|
64
|
-
version=config.version,
|
|
65
|
-
root_path=config.root_path,
|
|
66
|
-
debug=config.debug,
|
|
67
|
-
lifespan=lifespan,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
# TODO: Add CORS middleware Configuration
|
|
71
|
-
self._fastapi_app.add_middleware(
|
|
72
|
-
middleware_class=CORSMiddleware,
|
|
73
|
-
allow_origins=["*"],
|
|
74
|
-
allow_credentials=True,
|
|
75
|
-
allow_methods=["*"],
|
|
76
|
-
allow_headers=["*"],
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
if api_router is not None:
|
|
80
|
-
self._fastapi_app.include_router(router=api_router)
|
|
81
|
-
|
|
82
|
-
def get_asgi_app(self) -> FastAPI:
|
|
83
|
-
"""Get the ASGI application."""
|
|
84
|
-
return self._fastapi_app
|
|
85
|
-
|
|
86
|
-
async def __call__(self, scope: Any, receive: Any, send: Any) -> None:
|
|
87
|
-
"""Forward the call to the FastAPI app."""
|
|
88
|
-
return await self._fastapi_app.__call__(scope=scope, receive=receive, send=send)
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
"""Plugins manager abstract module."""
|
|
2
|
-
|
|
3
|
-
from abc import ABC
|
|
4
|
-
from importlib import import_module
|
|
5
|
-
from types import ModuleType
|
|
6
|
-
from typing import cast
|
|
7
|
-
|
|
8
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
9
|
-
|
|
10
|
-
from fastapi_factory_utilities.core.plugins import PluginsEnum
|
|
11
|
-
from fastapi_factory_utilities.core.protocols import (
|
|
12
|
-
BaseApplicationProtocol,
|
|
13
|
-
PluginProtocol,
|
|
14
|
-
)
|
|
15
|
-
from fastapi_factory_utilities.core.utils.configs import (
|
|
16
|
-
UnableToReadConfigFileError,
|
|
17
|
-
ValueErrorConfigError,
|
|
18
|
-
build_config_from_file_in_package,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
from .exceptions import ApplicationPluginManagerException
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class PluginsActivationList(BaseModel):
|
|
25
|
-
"""Model for the plugins activation list."""
|
|
26
|
-
|
|
27
|
-
model_config = ConfigDict(extra="forbid")
|
|
28
|
-
|
|
29
|
-
activate: list[PluginsEnum] = Field(default=list())
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class ApplicationPluginManagerAbstract(ABC):
|
|
33
|
-
"""Abstract class for the application plugin manager.
|
|
34
|
-
|
|
35
|
-
Responsibilities:
|
|
36
|
-
- Retrieve the plugins for the application.
|
|
37
|
-
- Check the pre-conditions for the plugins.
|
|
38
|
-
- Perform actions on startup for the plugins.
|
|
39
|
-
- Perform actions on shutdown for the plugins.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
PACKAGE_NAME: str = ""
|
|
43
|
-
|
|
44
|
-
PLUGIN_PACKAGE_NAME: str = "fastapi_factory_utilities.core.plugins"
|
|
45
|
-
|
|
46
|
-
def __init__(self, plugin_activation_list: PluginsActivationList | None = None) -> None:
|
|
47
|
-
"""Instanciate the application plugin manager."""
|
|
48
|
-
if self.PACKAGE_NAME == "":
|
|
49
|
-
raise ValueError("The package name must be set in the concrete plugin manager class.")
|
|
50
|
-
|
|
51
|
-
self._plugins: list[PluginProtocol] = []
|
|
52
|
-
self._plugins_activation_list: PluginsActivationList
|
|
53
|
-
if plugin_activation_list is not None:
|
|
54
|
-
self._plugins_activation_list = plugin_activation_list
|
|
55
|
-
else:
|
|
56
|
-
self._plugins_activation_list = self._build_plugins_activation_list()
|
|
57
|
-
|
|
58
|
-
self._check_pre_conditions()
|
|
59
|
-
|
|
60
|
-
def _check_pre_conditions(self) -> None:
|
|
61
|
-
"""Check the pre-conditions for the plugins.
|
|
62
|
-
|
|
63
|
-
Raises:
|
|
64
|
-
ApplicationPluginManagerException: If a plugin is not
|
|
65
|
-
activated.
|
|
66
|
-
|
|
67
|
-
"""
|
|
68
|
-
for plugin in self._plugins_activation_list.activate:
|
|
69
|
-
try:
|
|
70
|
-
plugin_module: ModuleType = import_module(name=f"{self.PLUGIN_PACKAGE_NAME}.{plugin.value}")
|
|
71
|
-
except ImportError as exception:
|
|
72
|
-
raise ApplicationPluginManagerException(f"Unable to import the plugin {plugin.value}") from exception
|
|
73
|
-
|
|
74
|
-
if not isinstance(plugin_module, PluginProtocol):
|
|
75
|
-
raise ApplicationPluginManagerException(
|
|
76
|
-
f"The plugin {plugin.value} does not implement the PluginProtocol"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
if not plugin_module.pre_conditions_check(application=cast(BaseApplicationProtocol, self)):
|
|
80
|
-
raise ApplicationPluginManagerException(f"The plugin {plugin.value} does not meet the pre-conditions")
|
|
81
|
-
|
|
82
|
-
self._plugins.append(plugin_module)
|
|
83
|
-
|
|
84
|
-
def _on_load(self) -> None:
|
|
85
|
-
"""Actions to perform on load for the plugins."""
|
|
86
|
-
for plugin in self._plugins:
|
|
87
|
-
plugin.on_load(application=cast(BaseApplicationProtocol, self))
|
|
88
|
-
|
|
89
|
-
def _build_plugins_activation_list(self) -> PluginsActivationList:
|
|
90
|
-
"""Build the plugins activation list.
|
|
91
|
-
|
|
92
|
-
Returns:
|
|
93
|
-
PluginsActivationList: The plugins activation list.
|
|
94
|
-
|
|
95
|
-
Raises:
|
|
96
|
-
ApplicationPluginManagerException: If there is an error
|
|
97
|
-
reading the configuration file.
|
|
98
|
-
ApplicationPluginManagerException: If there is an error
|
|
99
|
-
creating the configuration model.
|
|
100
|
-
|
|
101
|
-
"""
|
|
102
|
-
try:
|
|
103
|
-
config: PluginsActivationList = build_config_from_file_in_package(
|
|
104
|
-
package_name=self.PACKAGE_NAME,
|
|
105
|
-
filename="application.yaml",
|
|
106
|
-
config_class=PluginsActivationList,
|
|
107
|
-
yaml_base_key="plugins",
|
|
108
|
-
)
|
|
109
|
-
except UnableToReadConfigFileError as exception:
|
|
110
|
-
raise ApplicationPluginManagerException("Unable to read the application configuration file") from exception
|
|
111
|
-
except ValueErrorConfigError as exception:
|
|
112
|
-
raise ApplicationPluginManagerException(
|
|
113
|
-
"Unable to create the application configuration model"
|
|
114
|
-
) from exception
|
|
115
|
-
|
|
116
|
-
return config
|
|
117
|
-
|
|
118
|
-
async def plugins_on_startup(self) -> None:
|
|
119
|
-
"""Actions to perform on startup for the plugins."""
|
|
120
|
-
for plugin in self._plugins:
|
|
121
|
-
try:
|
|
122
|
-
await plugin.on_startup(application=cast(BaseApplicationProtocol, self))
|
|
123
|
-
except Exception as exception:
|
|
124
|
-
raise ApplicationPluginManagerException(
|
|
125
|
-
f"Error during the startup of the plugin {plugin.__class__.__name__}"
|
|
126
|
-
) from exception
|
|
127
|
-
|
|
128
|
-
async def plugins_on_shutdown(self) -> None:
|
|
129
|
-
"""Actions to perform on shutdown for the plugins."""
|
|
130
|
-
for plugin in self._plugins:
|
|
131
|
-
try:
|
|
132
|
-
await plugin.on_shutdown(application=cast(BaseApplicationProtocol, self))
|
|
133
|
-
except Exception as exception:
|
|
134
|
-
raise ApplicationPluginManagerException(
|
|
135
|
-
f"Error during the shutdown of the plugin {plugin.__class__.__name__}"
|
|
136
|
-
) from exception
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"""Provides the concrete application class."""
|
|
2
|
-
|
|
3
|
-
from typing import ClassVar
|
|
4
|
-
|
|
5
|
-
from beanie import Document
|
|
6
|
-
|
|
7
|
-
from fastapi_factory_utilities.core.app import BaseApplication
|
|
8
|
-
from fastapi_factory_utilities.core.app.base.plugins_manager_abstract import (
|
|
9
|
-
PluginsActivationList,
|
|
10
|
-
)
|
|
11
|
-
from fastapi_factory_utilities.example.models.books.document import BookDocument
|
|
12
|
-
|
|
13
|
-
from .config import AppConfig
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class App(BaseApplication):
|
|
17
|
-
"""Concrete application class."""
|
|
18
|
-
|
|
19
|
-
PACKAGE_NAME: str = "fastapi_factory_utilities.example"
|
|
20
|
-
|
|
21
|
-
CONFIG_CLASS = AppConfig
|
|
22
|
-
|
|
23
|
-
ODM_DOCUMENT_MODELS: ClassVar[list[type[Document]]] = [BookDocument]
|
|
24
|
-
|
|
25
|
-
def __init__(self, config: AppConfig, plugin_activation_list: PluginsActivationList | None = None) -> None:
|
|
26
|
-
"""Instantiate the application with the configuration and the API router.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
config (AppConfig): The application configuration.
|
|
30
|
-
plugin_activation_list (PluginsActivationList | None, optional): The plugins activation list.
|
|
31
|
-
"""
|
|
32
|
-
super().__init__(config=config, plugin_activation_list=plugin_activation_list)
|
|
33
|
-
|
|
34
|
-
# Prevent circular imports
|
|
35
|
-
from ..api import api_router # pylint: disable=import-outside-toplevel
|
|
36
|
-
|
|
37
|
-
self.get_asgi_app().include_router(router=api_router)
|