fastapi-factory-utilities 0.1.0__py3-none-any.whl → 0.2.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.

Potentially problematic release.


This version of fastapi-factory-utilities might be problematic. Click here for more details.

Files changed (53) hide show
  1. fastapi_factory_utilities/core/api/v1/sys/health.py +56 -12
  2. fastapi_factory_utilities/core/api/v1/sys/readiness.py +19 -12
  3. fastapi_factory_utilities/core/app/__init__.py +7 -12
  4. fastapi_factory_utilities/core/app/application.py +133 -0
  5. fastapi_factory_utilities/core/app/builder.py +123 -0
  6. fastapi_factory_utilities/core/app/config.py +164 -0
  7. fastapi_factory_utilities/core/app/exceptions.py +20 -0
  8. fastapi_factory_utilities/core/app/fastapi_builder.py +85 -0
  9. fastapi_factory_utilities/core/app/plugin_manager/__init__.py +15 -0
  10. fastapi_factory_utilities/core/app/plugin_manager/exceptions.py +33 -0
  11. fastapi_factory_utilities/core/app/plugin_manager/plugin_manager.py +190 -0
  12. fastapi_factory_utilities/core/exceptions.py +43 -0
  13. fastapi_factory_utilities/core/plugins/__init__.py +21 -0
  14. fastapi_factory_utilities/core/plugins/example/__init__.py +31 -0
  15. fastapi_factory_utilities/core/plugins/httpx_plugin/__init__.py +31 -0
  16. fastapi_factory_utilities/core/plugins/odm_plugin/__init__.py +74 -17
  17. fastapi_factory_utilities/core/plugins/odm_plugin/builder.py +27 -35
  18. fastapi_factory_utilities/core/plugins/odm_plugin/configs.py +1 -3
  19. fastapi_factory_utilities/core/plugins/odm_plugin/depends.py +30 -0
  20. fastapi_factory_utilities/core/plugins/opentelemetry_plugin/__init__.py +5 -5
  21. fastapi_factory_utilities/core/plugins/opentelemetry_plugin/builder.py +7 -7
  22. fastapi_factory_utilities/core/protocols.py +19 -16
  23. fastapi_factory_utilities/core/services/status/__init__.py +14 -0
  24. fastapi_factory_utilities/core/services/status/enums.py +30 -0
  25. fastapi_factory_utilities/core/services/status/exceptions.py +27 -0
  26. fastapi_factory_utilities/core/services/status/health_calculator_strategies.py +48 -0
  27. fastapi_factory_utilities/core/services/status/readiness_calculator_strategies.py +41 -0
  28. fastapi_factory_utilities/core/services/status/services.py +218 -0
  29. fastapi_factory_utilities/core/services/status/types.py +128 -0
  30. fastapi_factory_utilities/core/utils/configs.py +1 -1
  31. fastapi_factory_utilities/core/utils/status.py +71 -0
  32. fastapi_factory_utilities/core/utils/uvicorn.py +7 -8
  33. fastapi_factory_utilities/example/__init__.py +3 -3
  34. fastapi_factory_utilities/example/api/books/routes.py +7 -10
  35. fastapi_factory_utilities/example/app.py +50 -0
  36. fastapi_factory_utilities/example/application.yaml +5 -9
  37. fastapi_factory_utilities/example/services/books/__init__.py +2 -2
  38. fastapi_factory_utilities/example/services/books/services.py +9 -0
  39. {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.0.dist-info}/METADATA +6 -4
  40. fastapi_factory_utilities-0.2.0.dist-info/RECORD +70 -0
  41. {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.0.dist-info}/WHEEL +1 -1
  42. fastapi_factory_utilities/core/app/base/__init__.py +0 -17
  43. fastapi_factory_utilities/core/app/base/application.py +0 -123
  44. fastapi_factory_utilities/core/app/base/config_abstract.py +0 -78
  45. fastapi_factory_utilities/core/app/base/exceptions.py +0 -25
  46. fastapi_factory_utilities/core/app/base/fastapi_application_abstract.py +0 -88
  47. fastapi_factory_utilities/core/app/base/plugins_manager_abstract.py +0 -136
  48. fastapi_factory_utilities/example/app/__init__.py +0 -6
  49. fastapi_factory_utilities/example/app/app.py +0 -37
  50. fastapi_factory_utilities/example/app/config.py +0 -12
  51. fastapi_factory_utilities-0.1.0.dist-info/RECORD +0 -58
  52. {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.0.dist-info}/LICENSE +0 -0
  53. {fastapi_factory_utilities-0.1.0.dist-info → fastapi_factory_utilities-0.2.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,70 @@
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-0.2.0.dist-info/LICENSE,sha256=iO1nLzMMst6vEiqgSUrfrbetM7b0bvdzXhbed5tqG8o,1074
67
+ fastapi_factory_utilities-0.2.0.dist-info/METADATA,sha256=ROGr-AWsaQ1tLxOx0YTZCk6ayy84W2wa2ZrXmZbjRIc,3314
68
+ fastapi_factory_utilities-0.2.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
69
+ fastapi_factory_utilities-0.2.0.dist-info/entry_points.txt,sha256=IK0VcBexXo4uXQmTrbfhhnnfq4GmXPRn0GBB8hzlsq4,101
70
+ fastapi_factory_utilities-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 2.1.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -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,6 +0,0 @@
1
- """Provides the App and AppConfig classes."""
2
-
3
- from .app import App
4
- from .config import AppConfig
5
-
6
- __all__: list[str] = ["App", "AppConfig"]
@@ -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)
@@ -1,12 +0,0 @@
1
- """Provides the application configuration."""
2
-
3
- from fastapi_factory_utilities.core.app import AppConfigAbstract
4
-
5
-
6
- class AppConfig(AppConfigAbstract):
7
- """The application configuration.
8
-
9
- Values are set in application.yaml.
10
- """
11
-
12
- pass