fastapi-factory-utilities 0.5.0__py3-none-any.whl → 0.6.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 (39) hide show
  1. fastapi_factory_utilities/core/api/v1/sys/health.py +1 -1
  2. fastapi_factory_utilities/core/app/application.py +22 -26
  3. fastapi_factory_utilities/core/app/builder.py +8 -32
  4. fastapi_factory_utilities/core/app/fastapi_builder.py +3 -3
  5. fastapi_factory_utilities/core/plugins/__init__.py +2 -31
  6. fastapi_factory_utilities/core/plugins/abstracts.py +40 -0
  7. fastapi_factory_utilities/core/plugins/aiopika/__init__.py +23 -0
  8. fastapi_factory_utilities/core/plugins/aiopika/abstract.py +48 -0
  9. fastapi_factory_utilities/core/plugins/aiopika/configs.py +85 -0
  10. fastapi_factory_utilities/core/plugins/aiopika/exceptions.py +29 -0
  11. fastapi_factory_utilities/core/plugins/aiopika/exchange.py +70 -0
  12. fastapi_factory_utilities/core/plugins/aiopika/listener/__init__.py +7 -0
  13. fastapi_factory_utilities/core/plugins/aiopika/listener/abstract.py +72 -0
  14. fastapi_factory_utilities/core/plugins/aiopika/message.py +86 -0
  15. fastapi_factory_utilities/core/plugins/aiopika/plugins.py +63 -0
  16. fastapi_factory_utilities/core/plugins/aiopika/publisher/__init__.py +7 -0
  17. fastapi_factory_utilities/core/plugins/aiopika/publisher/abstract.py +66 -0
  18. fastapi_factory_utilities/core/plugins/aiopika/queue.py +86 -0
  19. fastapi_factory_utilities/core/plugins/odm_plugin/__init__.py +11 -156
  20. fastapi_factory_utilities/core/plugins/odm_plugin/builder.py +1 -1
  21. fastapi_factory_utilities/core/plugins/odm_plugin/configs.py +1 -1
  22. fastapi_factory_utilities/core/plugins/odm_plugin/documents.py +1 -1
  23. fastapi_factory_utilities/core/plugins/odm_plugin/plugins.py +155 -0
  24. fastapi_factory_utilities/core/plugins/opentelemetry_plugin/__init__.py +8 -121
  25. fastapi_factory_utilities/core/plugins/opentelemetry_plugin/instruments/__init__.py +85 -0
  26. fastapi_factory_utilities/core/plugins/opentelemetry_plugin/plugins.py +137 -0
  27. fastapi_factory_utilities/core/protocols.py +1 -54
  28. fastapi_factory_utilities/core/security/jwt.py +3 -3
  29. fastapi_factory_utilities/example/app.py +13 -4
  30. {fastapi_factory_utilities-0.5.0.dist-info → fastapi_factory_utilities-0.6.0.dist-info}/METADATA +4 -2
  31. {fastapi_factory_utilities-0.5.0.dist-info → fastapi_factory_utilities-0.6.0.dist-info}/RECORD +34 -23
  32. fastapi_factory_utilities/core/app/plugin_manager/__init__.py +0 -15
  33. fastapi_factory_utilities/core/app/plugin_manager/exceptions.py +0 -33
  34. fastapi_factory_utilities/core/app/plugin_manager/plugin_manager.py +0 -189
  35. fastapi_factory_utilities/core/plugins/example/__init__.py +0 -31
  36. fastapi_factory_utilities/core/plugins/httpx_plugin/__init__.py +0 -31
  37. {fastapi_factory_utilities-0.5.0.dist-info → fastapi_factory_utilities-0.6.0.dist-info}/WHEEL +0 -0
  38. {fastapi_factory_utilities-0.5.0.dist-info → fastapi_factory_utilities-0.6.0.dist-info}/entry_points.txt +0 -0
  39. {fastapi_factory_utilities-0.5.0.dist-info → fastapi_factory_utilities-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,130 +1,17 @@
1
1
  """OpenTelemetry Plugin Module."""
2
2
 
3
- import asyncio
4
- from typing import cast
5
-
6
- from opentelemetry.instrumentation.aiohttp_client import AioHttpClientInstrumentor
7
- from opentelemetry.instrumentation.fastapi import ( # pyright: ignore[reportMissingTypeStubs]
8
- FastAPIInstrumentor,
9
- )
10
- from opentelemetry.sdk.metrics import MeterProvider
11
- from opentelemetry.sdk.trace import TracerProvider
12
- from structlog.stdlib import BoundLogger, get_logger
13
-
14
- from fastapi_factory_utilities.core.protocols import ApplicationAbstractProtocol
15
-
16
- from .builder import OpenTelemetryPluginBuilder
17
- from .configs import OpenTelemetryConfig
3
+ from .configs import OpenTelemetryConfig, OpenTelemetryMeterConfig, OpenTelemetryTracerConfig
18
4
  from .exceptions import OpenTelemetryPluginBaseException, OpenTelemetryPluginConfigError
5
+ from .plugins import OpenTelemetryPlugin, depends_meter_provider, depends_otel_config, depends_tracer_provider
19
6
 
20
7
  __all__: list[str] = [
21
8
  "OpenTelemetryConfig",
9
+ "OpenTelemetryMeterConfig",
10
+ "OpenTelemetryPlugin",
22
11
  "OpenTelemetryPluginBaseException",
23
- "OpenTelemetryPluginBuilder",
24
12
  "OpenTelemetryPluginConfigError",
13
+ "OpenTelemetryTracerConfig",
14
+ "depends_meter_provider",
15
+ "depends_otel_config",
16
+ "depends_tracer_provider",
25
17
  ]
26
-
27
- _logger: BoundLogger = get_logger()
28
-
29
-
30
- def pre_conditions_check(application: ApplicationAbstractProtocol) -> bool:
31
- """Check the pre-conditions for the OpenTelemetry plugin.
32
-
33
- Args:
34
- application (BaseApplicationProtocol): The application.
35
-
36
- Returns:
37
- bool: True if the pre-conditions are met, False otherwise.
38
- """
39
- del application
40
- return True
41
-
42
-
43
- def on_load(
44
- application: ApplicationAbstractProtocol,
45
- ) -> None:
46
- """Actions to perform on load for the OpenTelemetry plugin.
47
-
48
- Args:
49
- application (BaseApplicationProtocol): The application.
50
- """
51
- # Build the OpenTelemetry Resources, TracerProvider and MeterProvider
52
- try:
53
- otel_builder: OpenTelemetryPluginBuilder = OpenTelemetryPluginBuilder(application=application).build_all()
54
- except OpenTelemetryPluginBaseException as exception:
55
- _logger.error(f"OpenTelemetry plugin failed to start. {exception}")
56
- return
57
- # Configuration is never None at this point (checked in the builder and raises an exception)
58
- otel_config: OpenTelemetryConfig = cast(OpenTelemetryConfig, otel_builder.config)
59
- # Save as state in the FastAPI application
60
- application.get_asgi_app().state.tracer_provider = otel_builder.tracer_provider
61
- application.get_asgi_app().state.meter_provider = otel_builder.meter_provider
62
- application.get_asgi_app().state.otel_config = otel_config
63
- # Instrument the FastAPI application
64
- FastAPIInstrumentor.instrument_app( # pyright: ignore[reportUnknownMemberType]
65
- app=application.get_asgi_app(),
66
- tracer_provider=otel_builder.tracer_provider,
67
- meter_provider=otel_builder.meter_provider,
68
- excluded_urls=otel_config.excluded_urls,
69
- )
70
- # Instrument the AioHttpClient
71
- AioHttpClientInstrumentor().instrument( # pyright: ignore[reportUnknownMemberType]
72
- tracer_provider=otel_builder.tracer_provider,
73
- meter_provider=otel_builder.meter_provider,
74
- )
75
-
76
- _logger.debug(f"OpenTelemetry plugin loaded. {otel_config.activate=}")
77
-
78
-
79
- async def on_startup(
80
- application: ApplicationAbstractProtocol,
81
- ) -> None:
82
- """Actions to perform on startup for the OpenTelemetry plugin.
83
-
84
- Args:
85
- application (BaseApplicationProtocol): The application.
86
-
87
- Returns:
88
- None
89
- """
90
- del application
91
- _logger.debug("OpenTelemetry plugin started.")
92
-
93
-
94
- async def on_shutdown(application: ApplicationAbstractProtocol) -> None:
95
- """Actions to perform on shutdown for the OpenTelemetry plugin.
96
-
97
- Args:
98
- application (BaseApplicationProtocol): The application.
99
-
100
- Returns:
101
- None
102
- """
103
- tracer_provider: TracerProvider = application.get_asgi_app().state.tracer_provider
104
- meter_provider: MeterProvider = application.get_asgi_app().state.meter_provider
105
- otel_config: OpenTelemetryConfig = application.get_asgi_app().state.otel_config
106
-
107
- seconds_to_ms_multiplier: int = 1000
108
-
109
- async def close_tracer_provider() -> None:
110
- """Close the tracer provider."""
111
- tracer_provider.force_flush(timeout_millis=otel_config.closing_timeout * seconds_to_ms_multiplier)
112
- # No Delay for the shutdown of the tracer provider
113
- tracer_provider.shutdown()
114
-
115
- async def close_meter_provider() -> None:
116
- """Close the meter provider.
117
-
118
- Split the timeout in half for the flush and shutdown.
119
- """
120
- meter_provider.force_flush(timeout_millis=int(otel_config.closing_timeout / 2) * seconds_to_ms_multiplier)
121
- meter_provider.shutdown(timeout_millis=int(otel_config.closing_timeout / 2) * seconds_to_ms_multiplier)
122
-
123
- _logger.debug("OpenTelemetry plugin stop requested. Flushing and closing...")
124
-
125
- await asyncio.gather(
126
- close_tracer_provider(),
127
- close_meter_provider(),
128
- )
129
-
130
- _logger.debug("OpenTelemetry plugin closed.")
@@ -0,0 +1,85 @@
1
+ """Instruments for the OpenTelemetry plugin."""
2
+
3
+ # pyright: reportMissingTypeStubs=false
4
+
5
+ from collections.abc import Callable
6
+ from importlib.util import find_spec
7
+ from typing import Any
8
+
9
+ from opentelemetry.sdk.metrics import MeterProvider
10
+ from opentelemetry.sdk.trace import TracerProvider
11
+
12
+ from fastapi_factory_utilities.core.plugins.opentelemetry_plugin.configs import OpenTelemetryConfig
13
+ from fastapi_factory_utilities.core.protocols import ApplicationAbstractProtocol
14
+
15
+
16
+ def instrument_fastapi(
17
+ application: ApplicationAbstractProtocol,
18
+ config: OpenTelemetryConfig,
19
+ meter_provider: MeterProvider,
20
+ tracer_provider: TracerProvider,
21
+ ) -> None:
22
+ """Instrument the FastAPI application."""
23
+ if find_spec(name="fastapi") and find_spec(name="opentelemetry.instrumentation.fastapi"):
24
+ from opentelemetry.instrumentation.fastapi import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
25
+ FastAPIInstrumentor,
26
+ )
27
+
28
+ excluded_urls_str: str | None = None if len(config.excluded_urls) == 0 else ",".join(config.excluded_urls)
29
+ FastAPIInstrumentor.instrument_app( # pyright: ignore[reportUnknownMemberType]
30
+ app=application.get_asgi_app(),
31
+ tracer_provider=tracer_provider,
32
+ meter_provider=meter_provider,
33
+ excluded_urls=excluded_urls_str,
34
+ )
35
+
36
+
37
+ def instrument_aiohttp(
38
+ application: ApplicationAbstractProtocol, # pylint: disable=unused-argument
39
+ config: OpenTelemetryConfig, # pylint: disable=unused-argument
40
+ meter_provider: MeterProvider,
41
+ tracer_provider: TracerProvider,
42
+ ) -> None:
43
+ """Instrument the Aiohttp application.
44
+
45
+ Args:
46
+ application (ApplicationAbstractProtocol): The application.
47
+ config (OpenTelemetryConfig): The configuration.
48
+ meter_provider (MeterProvider): The meter provider.
49
+ tracer_provider (TracerProvider): The tracer provider.
50
+
51
+ Returns:
52
+ None
53
+ """
54
+ if find_spec(name="aiohttp") and find_spec(name="opentelemetry.instrumentation.aiohttp_client"):
55
+ from opentelemetry.instrumentation.aiohttp_client import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
56
+ AioHttpClientInstrumentor,
57
+ )
58
+
59
+ AioHttpClientInstrumentor().instrument( # pyright: ignore[reportUnknownMemberType]
60
+ tracer_provider=tracer_provider,
61
+ meter_provider=meter_provider,
62
+ )
63
+
64
+
65
+ def instrument_aio_pika(
66
+ application: ApplicationAbstractProtocol, # pylint: disable=unused-argument
67
+ config: OpenTelemetryConfig, # pylint: disable=unused-argument
68
+ meter_provider: MeterProvider,
69
+ tracer_provider: TracerProvider,
70
+ ) -> None:
71
+ """Instrument the AioPika application."""
72
+ if find_spec(name="aio_pika") and find_spec(name="opentelemetry.instrumentation.aio_pika"):
73
+ from opentelemetry.instrumentation.aio_pika import ( # pylint: disable=import-outside-toplevel # noqa: PLC0415
74
+ AioPikaInstrumentor,
75
+ )
76
+
77
+ AioPikaInstrumentor().instrument( # pyright: ignore[reportUnknownMemberType]
78
+ tracer_provider=tracer_provider,
79
+ meter_provider=meter_provider,
80
+ )
81
+
82
+
83
+ INSTRUMENTS: list[Callable[..., Any]] = [instrument_fastapi, instrument_aiohttp, instrument_aio_pika]
84
+
85
+ __all__: list[str] = ["INSTRUMENTS"]
@@ -0,0 +1,137 @@
1
+ """Provides the OpenTelemetry plugin."""
2
+
3
+ import asyncio
4
+ from typing import Self, cast
5
+
6
+ from fastapi import Request
7
+ from opentelemetry.sdk.metrics import MeterProvider
8
+ from opentelemetry.sdk.trace import TracerProvider
9
+ from structlog.stdlib import BoundLogger, get_logger
10
+
11
+ from fastapi_factory_utilities.core.plugins.abstracts import PluginAbstract
12
+
13
+ from .builder import OpenTelemetryPluginBuilder
14
+ from .configs import OpenTelemetryConfig
15
+ from .exceptions import OpenTelemetryPluginBaseException, OpenTelemetryPluginConfigError
16
+ from .instruments import INSTRUMENTS
17
+
18
+ __all__: list[str] = [
19
+ "OpenTelemetryConfig",
20
+ "OpenTelemetryPluginBaseException",
21
+ "OpenTelemetryPluginBuilder",
22
+ "OpenTelemetryPluginConfigError",
23
+ ]
24
+
25
+ _logger: BoundLogger = get_logger()
26
+
27
+
28
+ class OpenTelemetryPlugin(PluginAbstract):
29
+ """OpenTelemetry plugin."""
30
+
31
+ SECONDS_TO_MS_MULTIPLIER: int = 1000
32
+
33
+ def __init__(self) -> None:
34
+ """Initialize the OpenTelemetry plugin."""
35
+ super().__init__()
36
+ self._otel_config: OpenTelemetryConfig | None = None
37
+ self._tracer_provider: TracerProvider | None = None
38
+ self._meter_provider: MeterProvider | None = None
39
+
40
+ def _build(self) -> Self:
41
+ """Build the OpenTelemetry plugin."""
42
+ assert self._application is not None
43
+ # Build the OpenTelemetry Resources, TracerProvider and MeterProvider
44
+ try:
45
+ otel_builder: OpenTelemetryPluginBuilder = OpenTelemetryPluginBuilder(
46
+ application=self._application
47
+ ).build_all()
48
+ except OpenTelemetryPluginBaseException as exception:
49
+ _logger.error(f"OpenTelemetry plugin failed to start. {exception}")
50
+ raise
51
+ # Configuration is never None at this point (checked in the builder and raises an exception)
52
+ self._otel_config = cast(OpenTelemetryConfig, otel_builder.config)
53
+ self._tracer_provider = otel_builder.tracer_provider
54
+ self._meter_provider = otel_builder.meter_provider
55
+ return self
56
+
57
+ def _instrument(self) -> None:
58
+ """Instrument the FastAPI application."""
59
+ assert self._application is not None
60
+ assert self._tracer_provider is not None
61
+ assert self._meter_provider is not None
62
+ assert self._otel_config is not None
63
+
64
+ for instrument in INSTRUMENTS:
65
+ instrument(self._application, self._otel_config, self._meter_provider, self._tracer_provider)
66
+
67
+ def on_load(self) -> None:
68
+ """On load."""
69
+ assert self._application is not None
70
+ # Build the OpenTelemetry Resources, TracerProvider and MeterProvider
71
+ self._build()
72
+ assert self._tracer_provider is not None
73
+ assert self._meter_provider is not None
74
+ assert self._otel_config is not None
75
+ self._add_to_state(key="tracer_provider", value=self._tracer_provider)
76
+ self._add_to_state(key="meter_provider", value=self._meter_provider)
77
+ self._add_to_state(key="otel_config", value=self._otel_config)
78
+ # Instrument the FastAPI application and AioHttpClient, ...
79
+ self._instrument()
80
+ _logger.debug(f"OpenTelemetry plugin loaded. {self._otel_config.activate=}")
81
+
82
+ async def on_startup(self) -> None:
83
+ """On startup."""
84
+ pass
85
+
86
+ async def close_tracer_provider(self) -> None:
87
+ """Close the tracer provider."""
88
+ assert self._tracer_provider is not None
89
+ assert self._otel_config is not None
90
+ self._tracer_provider.force_flush(
91
+ timeout_millis=self._otel_config.closing_timeout * self.SECONDS_TO_MS_MULTIPLIER
92
+ )
93
+ # No Delay for the shutdown of the tracer provider
94
+ try:
95
+ self._tracer_provider.shutdown()
96
+ except Exception as exception: # pylint: disable=broad-exception-caught
97
+ _logger.error("OpenTelemetry plugin failed to close the tracer provider.", error=exception)
98
+
99
+ async def close_meter_provider(self) -> None:
100
+ """Close the meter provider."""
101
+ assert self._meter_provider is not None
102
+ assert self._otel_config is not None
103
+ self._meter_provider.force_flush(
104
+ timeout_millis=self._otel_config.closing_timeout * self.SECONDS_TO_MS_MULTIPLIER
105
+ )
106
+ try:
107
+ self._meter_provider.shutdown(
108
+ timeout_millis=self._otel_config.closing_timeout * self.SECONDS_TO_MS_MULTIPLIER
109
+ )
110
+ except Exception as exception: # pylint: disable=broad-exception-caught
111
+ _logger.error("OpenTelemetry plugin failed to close the meter provider.", error=exception)
112
+
113
+ async def on_shutdown(self) -> None:
114
+ """On shutdown."""
115
+ _logger.debug("OpenTelemetry plugin stop requested. Flushing and closing...")
116
+
117
+ await asyncio.gather(
118
+ self.close_tracer_provider(),
119
+ self.close_meter_provider(),
120
+ )
121
+
122
+ _logger.debug("OpenTelemetry plugin closed.")
123
+
124
+
125
+ def depends_tracer_provider(request: Request) -> TracerProvider:
126
+ """Get the tracer provider."""
127
+ return request.app.state.tracer_provider
128
+
129
+
130
+ def depends_meter_provider(request: Request) -> MeterProvider:
131
+ """Get the meter provider."""
132
+ return request.app.state.meter_provider
133
+
134
+
135
+ def depends_otel_config(request: Request) -> OpenTelemetryConfig:
136
+ """Get the OpenTelemetry config."""
137
+ return request.app.state.otel_config
@@ -1,17 +1,15 @@
1
1
  """Protocols for the base application."""
2
2
 
3
3
  from abc import abstractmethod
4
- from typing import TYPE_CHECKING, ClassVar, Protocol, runtime_checkable
4
+ from typing import TYPE_CHECKING, ClassVar, Protocol
5
5
 
6
6
  from beanie import Document
7
7
  from fastapi import FastAPI
8
8
 
9
- from fastapi_factory_utilities.core.plugins import PluginsEnum
10
9
  from fastapi_factory_utilities.core.services.status.services import StatusService
11
10
 
12
11
  if TYPE_CHECKING:
13
12
  from fastapi_factory_utilities.core.app.config import RootConfig
14
- from fastapi_factory_utilities.core.plugins import PluginState
15
13
 
16
14
 
17
15
  class ApplicationAbstractProtocol(Protocol):
@@ -21,8 +19,6 @@ class ApplicationAbstractProtocol(Protocol):
21
19
 
22
20
  ODM_DOCUMENT_MODELS: ClassVar[list[type[Document]]]
23
21
 
24
- DEFAULT_PLUGINS_ACTIVATED: ClassVar[list[PluginsEnum]]
25
-
26
22
  @abstractmethod
27
23
  def get_config(self) -> "RootConfig":
28
24
  """Get the application configuration."""
@@ -34,52 +30,3 @@ class ApplicationAbstractProtocol(Protocol):
34
30
  @abstractmethod
35
31
  def get_status_service(self) -> StatusService:
36
32
  """Get the status service."""
37
-
38
-
39
- @runtime_checkable
40
- class PluginProtocol(Protocol):
41
- """Defines the protocol for the plugins."""
42
-
43
- @abstractmethod
44
- def pre_conditions_check(self, application: ApplicationAbstractProtocol) -> bool:
45
- """Check the pre-conditions for the plugin.
46
-
47
- Args:
48
- application (BaseApplicationProtocol): The application.
49
-
50
- Returns:
51
- bool: True if the pre-conditions are met, False otherwise.
52
- """
53
-
54
- @abstractmethod
55
- def on_load(self, application: ApplicationAbstractProtocol) -> list["PluginState"] | None:
56
- """The actions to perform on load for the plugin.
57
-
58
- Args:
59
- application (BaseApplicationProtocol): The application.
60
-
61
- Returns:
62
- None
63
- """
64
-
65
- @abstractmethod
66
- async def on_startup(self, application: ApplicationAbstractProtocol) -> list["PluginState"] | None:
67
- """The actions to perform on startup for the plugin.
68
-
69
- Args:
70
- application (BaseApplicationProtocol): The application.
71
-
72
- Returns:
73
- None
74
- """
75
-
76
- @abstractmethod
77
- async def on_shutdown(self, application: ApplicationAbstractProtocol) -> None:
78
- """The actions to perform on shutdown for the plugin.
79
-
80
- Args:
81
- application (BaseApplicationProtocol): The application.
82
-
83
- Returns:
84
- None
85
- """
@@ -140,11 +140,11 @@ class JWTBearerAuthentication:
140
140
  # by the request or by the jwt parameter
141
141
  if self.jwt_raw is None and request is None:
142
142
  raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail="Missing Credentials")
143
-
143
+ jwt_raw: str
144
144
  if self.jwt_raw is None:
145
- jwt_raw: str = self._extract_raw_token(request=request) # type: ignore[arg-type]
145
+ jwt_raw = self._extract_raw_token(request=request) # type: ignore[arg-type]
146
146
  else:
147
- jwt_raw: str = self.jwt_raw
147
+ jwt_raw = self.jwt_raw
148
148
 
149
149
  # Execute the io bound and cpu bound tasks in parallel
150
150
  async with TaskGroup() as tg:
@@ -7,7 +7,9 @@ from beanie import Document
7
7
  from fastapi_factory_utilities.core.app.application import ApplicationAbstract
8
8
  from fastapi_factory_utilities.core.app.builder import ApplicationGenericBuilder
9
9
  from fastapi_factory_utilities.core.app.config import RootConfig
10
- from fastapi_factory_utilities.core.plugins import PluginsEnum
10
+ from fastapi_factory_utilities.core.plugins.abstracts import PluginAbstract
11
+ from fastapi_factory_utilities.core.plugins.odm_plugin import ODMPlugin
12
+ from fastapi_factory_utilities.core.plugins.opentelemetry_plugin import OpenTelemetryPlugin
11
13
  from fastapi_factory_utilities.example.models.books.document import BookDocument
12
14
 
13
15
 
@@ -26,8 +28,6 @@ class App(ApplicationAbstract):
26
28
 
27
29
  ODM_DOCUMENT_MODELS: ClassVar[list[type[Document]]] = [BookDocument]
28
30
 
29
- DEFAULT_PLUGINS_ACTIVATED: ClassVar[list[PluginsEnum]] = [PluginsEnum.OPENTELEMETRY_PLUGIN, PluginsEnum.ODM_PLUGIN]
30
-
31
31
  def configure(self) -> None:
32
32
  """Configure the application."""
33
33
  # Prevent circular import
@@ -48,4 +48,13 @@ class App(ApplicationAbstract):
48
48
  class AppBuilder(ApplicationGenericBuilder[App]):
49
49
  """Application builder for the App application."""
50
50
 
51
- pass
51
+ def get_default_plugins(self) -> list[PluginAbstract]:
52
+ """Get the default plugins."""
53
+ return [ODMPlugin(), OpenTelemetryPlugin()]
54
+
55
+ def __init__(self, plugins: list[PluginAbstract] | None = None) -> None:
56
+ """Initialize the AppBuilder."""
57
+ # If no plugins are provided, use the default plugins
58
+ if plugins is None:
59
+ plugins = self.get_default_plugins()
60
+ super().__init__(plugins=plugins)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi_factory_utilities
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: Consolidate libraries and utilities to create microservices in Python with FastAPI, Beanie, Httpx, AioPika and OpenTelemetry.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -19,12 +19,14 @@ Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Topic :: Software Development :: Libraries
20
20
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
21
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Dist: aio-pika (>=9.5.7,<10.0.0)
22
23
  Requires-Dist: aiohttp[speedups] (>=3.12.13,<4.0.0)
23
24
  Requires-Dist: beanie (>=1.30.0,<2.0.0)
24
25
  Requires-Dist: fastapi (>=0.115.13,<1)
25
26
  Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (>=1.26.0,<2.0.0)
26
27
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.26.0,<2.0.0)
27
- Requires-Dist: opentelemetry-instrumentation-aiohttp-client (>=0.55b1,<0.56)
28
+ Requires-Dist: opentelemetry-instrumentation-aio-pika (>=0.59b0,<0.60)
29
+ Requires-Dist: opentelemetry-instrumentation-aiohttp-client (>=0,<1)
28
30
  Requires-Dist: opentelemetry-instrumentation-fastapi (>=0,<1)
29
31
  Requires-Dist: opentelemetry-instrumentation-pymongo (>=0,<1)
30
32
  Requires-Dist: opentelemetry-propagator-b3 (>=1.26.0,<2.0.0)
@@ -3,37 +3,48 @@ fastapi_factory_utilities/core/__init__.py,sha256=tt5a-MgeFt_oACkc9K5xl2rynIbca9
3
3
  fastapi_factory_utilities/core/api/__init__.py,sha256=fAwgRcRry1nIyAL7CsCbpwR87n5tWnBWKEPH6QZCpp8,542
4
4
  fastapi_factory_utilities/core/api/tags.py,sha256=3hQcTeW0FS78sPTJ2PB44dMDTSkoW-xKj7rrfKX2Lk0,154
5
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
6
+ fastapi_factory_utilities/core/api/v1/sys/health.py,sha256=LILUwfyqeBDlf4GSpkU_3bxMjZPCLanOBkMGDKtQufY,2867
7
7
  fastapi_factory_utilities/core/api/v1/sys/readiness.py,sha256=xIY8pQLShU7KWRtlOUK5gTDyZ8aB1KBvLczC6boT-tg,1711
8
8
  fastapi_factory_utilities/core/app/__init__.py,sha256=6Ee_zK-KzJWoOElsAnGdBz8giRJlhAPMaEzs0I3gvrA,596
9
- fastapi_factory_utilities/core/app/application.py,sha256=WrDXh00r_jzQTtZGeFO43lIzvDraplitejTaSJj_uFE,5091
10
- fastapi_factory_utilities/core/app/builder.py,sha256=XKtJuRxvaqzNdhfNXGkyyxEH4MkZCgAUjkqYnOws8n0,4728
9
+ fastapi_factory_utilities/core/app/application.py,sha256=fJTKgfqBWD1xzE7Y9ToZEBDrd1PxHtnZ7SHLmkS1S1M,4737
10
+ fastapi_factory_utilities/core/app/builder.py,sha256=gkmhGVYFu2zbW5sxWyh6Pn5ysdCIvn1_WqNJMKls54s,3820
11
11
  fastapi_factory_utilities/core/app/config.py,sha256=MuV4G_M4QgZWYHoulusJLv_m4Qr2php-Cg9Jum4qkNA,7303
12
12
  fastapi_factory_utilities/core/app/enums.py,sha256=X1upnaehYU0eHExXTde5xsH-pI9q7HZDNsOEF5PApdg,226
13
13
  fastapi_factory_utilities/core/app/exceptions.py,sha256=tQDf0_4j5xgCbku7TL7JaZGs3_bjsWG2YLBCydQJpPw,664
14
- fastapi_factory_utilities/core/app/fastapi_builder.py,sha256=KoywPbWu9wY5s1KpBAwxgqH07PYT3Y6Mtlq-PP4__5I,2852
15
- fastapi_factory_utilities/core/app/plugin_manager/__init__.py,sha256=hHk_fet3d41I-MzohGlvbNjqWQtAbxWaaEfbt41Zweo,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=b6wDStsjAdCKExFFNCFEmeMERNsVCeIp1qseKfn5TO4,6681
14
+ fastapi_factory_utilities/core/app/fastapi_builder.py,sha256=7egWkS98nTiVBe2Bw5dQzDBryQCkz4w7gnY9HA24NFg,2855
18
15
  fastapi_factory_utilities/core/exceptions.py,sha256=9s-i_RHPCsOswQPRvK8tyy-smE1118pytxWDJMNEl0M,2670
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=EyjshkhEseri659k7YISJEVH0-cpSlAWaKvhnCPNNbY,5797
23
- fastapi_factory_utilities/core/plugins/odm_plugin/builder.py,sha256=D6UUDOJYv6IWugilodi6x9fwj_kZkqzPfKT_pL9UW7c,8753
24
- fastapi_factory_utilities/core/plugins/odm_plugin/configs.py,sha256=zQoJC1wLNyq2pZyFhl0bKeNsTl4y_4_82BHCCaOEjCQ,331
16
+ fastapi_factory_utilities/core/plugins/__init__.py,sha256=7ctIv2Jx2uOUpgm8ITFRuZxHi6OXvlVS0VcbszVzvis,114
17
+ fastapi_factory_utilities/core/plugins/abstracts.py,sha256=p5iXmeOVD737G73I2keKV0Y-jLGQf2vYbTSR1LgrA14,1165
18
+ fastapi_factory_utilities/core/plugins/aiopika/__init__.py,sha256=U_9UEE76kA9WgMZBMT5mbet8kFzvorhcQEPuaW1yYk4,609
19
+ fastapi_factory_utilities/core/plugins/aiopika/abstract.py,sha256=TcvDwdaLV0UqFHQy6Sn3Y5Fp-1463dhL7VNB9LTKL5I,1682
20
+ fastapi_factory_utilities/core/plugins/aiopika/configs.py,sha256=BEPE8Ss7q_yCyuii4nywmIgh67iNLdhKxUm8tC0PdCY,3706
21
+ fastapi_factory_utilities/core/plugins/aiopika/exceptions.py,sha256=AkBKT8HVPpJDAntLNlOLp6lpQpKI-k8gxNzU24FsOF0,985
22
+ fastapi_factory_utilities/core/plugins/aiopika/exchange.py,sha256=tQfrv7-mX4lrHY1OTXB_aTkbg_brYniIuFisfFDSTT8,2509
23
+ fastapi_factory_utilities/core/plugins/aiopika/listener/__init__.py,sha256=LsTyu6kGoUm7c5OvSQTDJL7d8CG9TeARBHHVe_HGsHY,148
24
+ fastapi_factory_utilities/core/plugins/aiopika/listener/abstract.py,sha256=8po9iEWmNTFEc6K_ile5H-BHIeH9dxSaqVKp67xb6hk,2577
25
+ fastapi_factory_utilities/core/plugins/aiopika/message.py,sha256=Tn9pLZlkx238GA6SEav15Npq3TWu_dQ0NtzFWvPcPTM,2861
26
+ fastapi_factory_utilities/core/plugins/aiopika/plugins.py,sha256=0Oj9842Se3pGEUiHpIR4l7YTcKnfwkiH8Xjp7ykRddI,2214
27
+ fastapi_factory_utilities/core/plugins/aiopika/publisher/__init__.py,sha256=MGGdygH72xHZ4QAwvbUZKQt-_mPzLmMxHyAACSNnZ_c,151
28
+ fastapi_factory_utilities/core/plugins/aiopika/publisher/abstract.py,sha256=PmIG5zlx-tFUAneHtbknR0Ik5flz8pMTzxcreY2hZ7s,2494
29
+ fastapi_factory_utilities/core/plugins/aiopika/queue.py,sha256=u7iOOnv8EHO7q2qM6jDlYimajrjlQN8R3ftL61XgQIE,2794
30
+ fastapi_factory_utilities/core/plugins/odm_plugin/__init__.py,sha256=JsVz4GBiZRmm4qpUD1-Wsg2tRXTn-VO5fU-W1whZo4E,683
31
+ fastapi_factory_utilities/core/plugins/odm_plugin/builder.py,sha256=MdO1D0C9LQpoqtNFqgPwSYedLzXR6PArhkoJw6wzykg,8761
32
+ fastapi_factory_utilities/core/plugins/odm_plugin/configs.py,sha256=5bVbtsLwJhuIvt8FCzOvk002G8qFmZumWkN75bPKatc,331
25
33
  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=BFQYHxHBmTacJRfhZi2OffvT_RAFvAAiDVQAa_d6Y7w,1141
34
+ fastapi_factory_utilities/core/plugins/odm_plugin/documents.py,sha256=4aQNrD26d0S542_LYmxxm07Q8SWzbGe3PCpho6iWY5Q,1102
27
35
  fastapi_factory_utilities/core/plugins/odm_plugin/exceptions.py,sha256=acnKJB0lGAzDs-7-LjBap8shjP3iV1a7dw7ouPVF27o,551
28
36
  fastapi_factory_utilities/core/plugins/odm_plugin/helpers.py,sha256=s9iEujDZbTmTb9FByJAVUzLkjQpsciQT9dytkeosKuE,463
37
+ fastapi_factory_utilities/core/plugins/odm_plugin/plugins.py,sha256=0jsLtw4NxZB6bDcBLBvWHqB-RELoewsSXTJdAOGunSY,6443
29
38
  fastapi_factory_utilities/core/plugins/odm_plugin/repositories.py,sha256=GJ3ovlxzTpiJ2_XlgARtwn6j0SbQxxAray_r8QWvGok,11313
30
- fastapi_factory_utilities/core/plugins/opentelemetry_plugin/__init__.py,sha256=gXM-apuR1xdjVxfOzurF-db3SauKyeWjK_7SFWkVWxw,4689
39
+ fastapi_factory_utilities/core/plugins/opentelemetry_plugin/__init__.py,sha256=xXHn5dUxhgdDDQMpTHf3voolzS0E3zE2RFbtFHJzb38,641
31
40
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/builder.py,sha256=9npQImifYAbEg0lFG7KwZ8V78SNrPoaINgd8vKitdMw,12509
32
41
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/configs.py,sha256=pMG9leMB7rtdkdGFLIxXflV7bf9epGrrYPt2N97KZcM,3750
33
42
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/exceptions.py,sha256=CpsHayfQpP0zghN8y5PP6TBy-cXhHoNxBR--I86gAdE,327
34
43
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/helpers.py,sha256=qpTIzX67orJz7vy6SBIwRs24omMBoToJkhpurZRjPuk,1533
35
- fastapi_factory_utilities/core/protocols.py,sha256=TzZKr_KfmTphk2LL-TD2XzxNlLbihbGM2DxWMhc5lEQ,2428
36
- fastapi_factory_utilities/core/security/jwt.py,sha256=jO3FNOiqVvCCbvShUmCyfii8oLXNbYk_Sfsb_O29dng,5630
44
+ fastapi_factory_utilities/core/plugins/opentelemetry_plugin/instruments/__init__.py,sha256=lMtdd1DSDrFcXggf0qMpB1RJC7aBqWMpOBXxC8-bqPY,3307
45
+ fastapi_factory_utilities/core/plugins/opentelemetry_plugin/plugins.py,sha256=v9W4bqEljcRgeSL8pf-4yZ7SGXOFmxVoljthvcLdy6Q,5356
46
+ fastapi_factory_utilities/core/protocols.py,sha256=w5FQqMAZ_OulG5hQWkoOapNSnxsjBPq4EjvWNXXdI_c,859
47
+ fastapi_factory_utilities/core/security/jwt.py,sha256=BrP9EmtuOxjafHKluYzRtGdZYankv72iQgG49t9TgJw,5640
37
48
  fastapi_factory_utilities/core/security/kratos.py,sha256=yP9-TkELeXRPRYE9aQRlOPlwvaUJ7VQpyAea8ucWUfg,3364
38
49
  fastapi_factory_utilities/core/services/hydra/__init__.py,sha256=AKBYNc3zW5OsCLLeFSXqmDbWbQefHUJxstLpsXLQEUQ,369
39
50
  fastapi_factory_utilities/core/services/hydra/exceptions.py,sha256=ePMrfZturU2IVcxOebR0CbVKKqprce_fK-4UXbPPgNI,450
@@ -63,7 +74,7 @@ fastapi_factory_utilities/example/api/__init__.py,sha256=qI82eeSwVjR6jSkX1pxm8AL
63
74
  fastapi_factory_utilities/example/api/books/__init__.py,sha256=zXARBnjywJwg1XsLbcixYWcHH4uC9mF-kbbX4P8cVgA,160
64
75
  fastapi_factory_utilities/example/api/books/responses.py,sha256=21WeD6bdg0MCD_0vRHwmsL4W79iDcG9NnDLemXysc84,540
65
76
  fastapi_factory_utilities/example/api/books/routes.py,sha256=bwg8Bhvoj9vx2SdwunzFS-Z3cHECtjl_yGdo8MfiGEM,1529
66
- fastapi_factory_utilities/example/app.py,sha256=SkQwK2Z29I0Kz36wiWyoh2V_CvBexQ5LJ3Ka-npCQUI,1579
77
+ fastapi_factory_utilities/example/app.py,sha256=MInt71wnDEC9yqVJeT3hChj7DRmg7sI3Ta0KkfubdyU,2076
67
78
  fastapi_factory_utilities/example/application.yaml,sha256=5xRyFSuMxmgZ5Mikai94UqKYJ7PxJp8omlXobTjv14M,485
68
79
  fastapi_factory_utilities/example/entities/books/__init__.py,sha256=cpTMhLpenb359lOT9HHUv6DzKX8fKl4WCzcsB3ddk6Q,185
69
80
  fastapi_factory_utilities/example/entities/books/entities.py,sha256=rLE01lE7U6WizrD5ZHMRwkynd8_dWF6DltBFH61f-Do,405
@@ -76,8 +87,8 @@ fastapi_factory_utilities/example/models/books/repository.py,sha256=7K63uAsSEGZ2
76
87
  fastapi_factory_utilities/example/services/books/__init__.py,sha256=Z06yNRoA7Zg3TGN-Q9rrvJg6Bbx-qJw661MVwukV6vQ,148
77
88
  fastapi_factory_utilities/example/services/books/services.py,sha256=-x7d4hotUWLzWo5uImMjFmtNcSTHwWv2bfttIbYYKbA,5380
78
89
  fastapi_factory_utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- fastapi_factory_utilities-0.5.0.dist-info/METADATA,sha256=8f6MuYLqieqLs4cFDZ8a75dO4zmdcqVUDsYPb3wkP4k,3500
80
- fastapi_factory_utilities-0.5.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
81
- fastapi_factory_utilities-0.5.0.dist-info/entry_points.txt,sha256=IK0VcBexXo4uXQmTrbfhhnnfq4GmXPRn0GBB8hzlsq4,101
82
- fastapi_factory_utilities-0.5.0.dist-info/licenses/LICENSE,sha256=iO1nLzMMst6vEiqgSUrfrbetM7b0bvdzXhbed5tqG8o,1074
83
- fastapi_factory_utilities-0.5.0.dist-info/RECORD,,
90
+ fastapi_factory_utilities-0.6.0.dist-info/METADATA,sha256=T6w0jeZL3srYmEK2geExdfhqrucPUilLBNDCBY-PWrs,3605
91
+ fastapi_factory_utilities-0.6.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
92
+ fastapi_factory_utilities-0.6.0.dist-info/entry_points.txt,sha256=IK0VcBexXo4uXQmTrbfhhnnfq4GmXPRn0GBB8hzlsq4,101
93
+ fastapi_factory_utilities-0.6.0.dist-info/licenses/LICENSE,sha256=iO1nLzMMst6vEiqgSUrfrbetM7b0bvdzXhbed5tqG8o,1074
94
+ fastapi_factory_utilities-0.6.0.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- """Provide PluginManager."""
2
-
3
- from .exceptions import (
4
- InvalidPluginError,
5
- PluginManagerError,
6
- PluginPreConditionNotMetError,
7
- )
8
- from .plugin_manager import PluginManager
9
-
10
- __all__: list[str] = [
11
- "InvalidPluginError",
12
- "PluginManager",
13
- "PluginManagerError",
14
- "PluginPreConditionNotMetError",
15
- ]
@@ -1,33 +0,0 @@
1
- """Provide the exceptions for the plugin manager."""
2
-
3
- from fastapi_factory_utilities.core.exceptions import FastAPIFactoryUtilitiesError
4
-
5
-
6
- class PluginManagerError(FastAPIFactoryUtilitiesError):
7
- """Generic plugin manager error."""
8
-
9
-
10
- class InvalidPluginError(PluginManagerError):
11
- """The plugin is invalid."""
12
-
13
- def __init__(self, plugin_name: str, message: str) -> None:
14
- """Instantiate the exception.
15
-
16
- Args:
17
- plugin_name (str): The plugin name.
18
- message (str): The message
19
- """
20
- super().__init__(message=f"Invalid plugin: {plugin_name}, {message}")
21
-
22
-
23
- class PluginPreConditionNotMetError(PluginManagerError):
24
- """The plugin pre-condition is not met."""
25
-
26
- def __init__(self, plugin_name: str, message: str) -> None:
27
- """Instantiate the exception.
28
-
29
- Args:
30
- plugin_name (str): The plugin name.
31
- message (str): The message
32
- """
33
- super().__init__(message=f"Plugin pre-condition not met: {plugin_name}, {message}")