fastapi-factory-utilities 0.2.1__py3-none-any.whl → 0.2.3__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.

@@ -21,6 +21,7 @@ class ApplicationGenericBuilder(Generic[T]):
21
21
 
22
22
  def __init__(self, plugins_activation_list: list[PluginsEnum] | None = None) -> None:
23
23
  """Instanciate the ApplicationGenericBuilder."""
24
+ self._uvicorn_utils: UvicornUtils | None = None
24
25
  self._root_config: RootConfig | None = None
25
26
  self._plugin_manager: PluginManager | None = None
26
27
  self._fastapi_builder: FastAPIBuilder | None = None
@@ -109,11 +110,12 @@ class ApplicationGenericBuilder(Generic[T]):
109
110
 
110
111
  def build_as_uvicorn_utils(self) -> UvicornUtils:
111
112
  """Build the application and provide UvicornUtils."""
112
- return UvicornUtils(app=self.build())
113
+ self._uvicorn_utils = UvicornUtils(app=self.build())
114
+ return self._uvicorn_utils
113
115
 
114
116
  def build_and_serve(self) -> None:
115
117
  """Build the application and serve it with Uvicorn."""
116
- uvicorn_utils: UvicornUtils = self.build_as_uvicorn_utils()
118
+ uvicorn_utils: UvicornUtils = self._uvicorn_utils or self.build_as_uvicorn_utils()
117
119
 
118
120
  setup_log(mode=LogModeEnum.CONSOLE)
119
121
 
@@ -78,6 +78,7 @@ async def on_startup(
78
78
 
79
79
  try:
80
80
  odm_factory: ODMBuilder = ODMBuilder(application=application).build_all()
81
+ await odm_factory.wait_ping()
81
82
  except Exception as exception: # pylint: disable=broad-except
82
83
  _logger.error(f"ODM plugin failed to start. {exception}")
83
84
  # TODO: Report the error to the status_service
@@ -1,9 +1,9 @@
1
1
  """Provides the module for the ODM plugin."""
2
2
 
3
- import time
4
3
  from typing import Any, ClassVar, Self
5
4
 
6
5
  from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
6
+ from pymongo.server_api import ServerApi, ServerApiVersion
7
7
  from structlog.stdlib import get_logger
8
8
 
9
9
  from fastapi_factory_utilities.core.protocols import ApplicationAbstractProtocol
@@ -124,31 +124,34 @@ class ODMBuilder:
124
124
  raise ODMPluginConfigError("Unable to create the application configuration model.") from exception
125
125
  return self
126
126
 
127
- @classmethod
128
- def _wait_client_to_be_ready(cls, client: AsyncIOMotorClient[Any], timeout_s: int) -> None:
129
- """Wait for the ODM client to be ready.
130
-
131
- Args:
132
- client (AsyncIOMotorClient): The ODM client.
133
- timeout_s (int): The timeout in seconds.
134
-
135
- Raises:
136
- TimeoutError: If the ODM client is not ready in the given timeout.
137
- """
138
- start_time: float = time.time()
139
- message_time: float = time.time()
140
- while (time.time() - start_time) < (timeout_s):
141
- if len(client.nodes) > 0: # type: ignore
142
- _logger.info(f"Waiting {(time.time() - start_time)*cls.MS_TO_S}ms for the ODM client to be ready.")
143
- return
144
-
145
- if (time.time() - message_time) > 1:
146
- elaps_time: float = time.time() - start_time
147
- _logger.debug(f"Waiting for the ODM client to be ready. (from {int(elaps_time)}s) ")
148
- message_time = time.time()
149
- time.sleep(cls.SLEEP_TIME_S)
150
-
151
- raise TimeoutError("The ODM client is not ready in the given timeout.")
127
+ # ======
128
+ # KEEP IT, Waiting for additional tests
129
+ # @classmethod
130
+ # def _wait_client_to_be_ready(cls, client: AsyncIOMotorClient[Any], timeout_s: int) -> None:
131
+ # """Wait for the ODM client to be ready.
132
+
133
+ # Args:
134
+ # client (AsyncIOMotorClient): The ODM client.
135
+ # timeout_s (int): The timeout in seconds.
136
+
137
+ # Raises:
138
+ # TimeoutError: If the ODM client is not ready in the given timeout.
139
+ # """
140
+ # start_time: float = time.time()
141
+ # message_time: float = time.time()
142
+ # while (time.time() - start_time) < (timeout_s):
143
+ # if len(client.nodes) > 0: # type: ignore
144
+ # _logger.info(f"Waiting {(time.time() - start_time)*cls.MS_TO_S}ms for the ODM client to be ready.")
145
+ # return
146
+
147
+ # if (time.time() - message_time) > 1:
148
+ # elaps_time: float = time.time() - start_time
149
+ # _logger.debug(f"Waiting for the ODM client to be ready. (from {int(elaps_time)}s) ")
150
+ # message_time = time.time()
151
+ # time.sleep(cls.SLEEP_TIME_S)
152
+
153
+ # raise TimeoutError("The ODM client is not ready in the given timeout.")
154
+ # ======
152
155
 
153
156
  def build_client(
154
157
  self,
@@ -173,11 +176,13 @@ class ODMBuilder:
173
176
  self._odm_client = AsyncIOMotorClient(
174
177
  host=self._config.uri,
175
178
  connect=True,
176
- connectTimeoutMS=self._config.connection_timeout_s,
177
- serverSelectionTimeoutMS=self._config.connection_timeout_s,
179
+ connectTimeoutMS=self._config.connection_timeout_ms,
180
+ serverSelectionTimeoutMS=self._config.connection_timeout_ms,
181
+ server_api=ServerApi(version=ServerApiVersion.V1),
178
182
  )
179
183
 
180
- self._wait_client_to_be_ready(client=self._odm_client, timeout_s=self._config.connection_timeout_s)
184
+ # KEEP IT, Waiting for additional tests
185
+ # self._wait_client_to_be_ready(client=self._odm_client, timeout_s=self._config.connection_timeout_s)
181
186
 
182
187
  return self
183
188
 
@@ -229,3 +234,19 @@ class ODMBuilder:
229
234
  self.build_database()
230
235
 
231
236
  return self
237
+
238
+ async def wait_ping(self):
239
+ """Wait for the ODM client to be ready.
240
+
241
+ Returns:
242
+ Self: The ODM factory.
243
+ """
244
+ if self._odm_client is None:
245
+ raise ODMPluginConfigError(
246
+ "ODM client is not set. Provide the ODM client using " "build_client method or through parameter."
247
+ )
248
+
249
+ try:
250
+ await self._odm_client.admin.command("ping")
251
+ except Exception as exception: # pylint: disable=broad-except
252
+ raise ODMPluginConfigError("Unable to ping the ODM client.") from exception
@@ -12,4 +12,4 @@ class ODMConfig(BaseModel):
12
12
 
13
13
  database: str = "test"
14
14
 
15
- connection_timeout_s: int = 10
15
+ connection_timeout_ms: int = 1000
@@ -1,5 +1,8 @@
1
1
  """Provides utilities for the application."""
2
2
 
3
+ import os
4
+ from typing import Any
5
+
3
6
  import uvicorn
4
7
  import uvicorn.server
5
8
 
@@ -20,6 +23,29 @@ class UvicornUtils:
20
23
  None
21
24
  """
22
25
  self._app: ApplicationAbstractProtocol = app
26
+ self._ssl_keyfile: str | os.PathLike[str] | None = None
27
+ self._ssl_certfile: str | os.PathLike[str] | None = None
28
+ self._ssl_keyfile_password: str | None = None
29
+
30
+ def add_ssl_certificates(
31
+ self,
32
+ ssl_keyfile: str | os.PathLike[str] | None = None,
33
+ ssl_certfile: str | os.PathLike[str] | None = None,
34
+ ssl_keyfile_password: str | None = None,
35
+ ) -> None:
36
+ """Add SSL certificates to the application.
37
+
38
+ Args:
39
+ ssl_keyfile (str | os.PathLike[str] | None): The SSL key file.
40
+ ssl_certfile (str | os.PathLike[str] | None): The SSL certificate file.
41
+ ssl_keyfile_password (str | None): The SSL key file password.
42
+
43
+ Returns:
44
+ None
45
+ """
46
+ self._ssl_keyfile = ssl_keyfile
47
+ self._ssl_certfile = ssl_certfile
48
+ self._ssl_keyfile_password = ssl_keyfile_password
23
49
 
24
50
  def build_uvicorn_config(self) -> uvicorn.Config:
25
51
  """Build the Uvicorn configuration.
@@ -27,12 +53,22 @@ class UvicornUtils:
27
53
  Returns:
28
54
  uvicorn.Config: The Uvicorn configuration.
29
55
  """
56
+ kwargs: dict[str, Any] = {}
57
+
58
+ if self._ssl_keyfile:
59
+ kwargs["ssl_keyfile"] = self._ssl_keyfile
60
+ if self._ssl_certfile:
61
+ kwargs["ssl_certfile"] = self._ssl_certfile
62
+ if self._ssl_keyfile_password:
63
+ kwargs["ssl_keyfile_password"] = self._ssl_keyfile_password
64
+
30
65
  config = uvicorn.Config(
31
66
  app=self._app.get_asgi_app(),
32
67
  host=self._app.get_config().server.host,
33
68
  port=self._app.get_config().server.port,
34
69
  reload=self._app.get_config().development.reload,
35
70
  workers=self._app.get_config().server.workers,
71
+ **kwargs,
36
72
  )
37
73
  clean_uvicorn_logger()
38
74
  return config
@@ -29,7 +29,7 @@ class UnableToReadYamlFileError(Exception):
29
29
  class YamlFileReader:
30
30
  """Handles reading YAML files and converting them to Pydantic models."""
31
31
 
32
- re_pattern: re.Pattern[str] = re.compile(r"\${([A-Za-z0-9\-\_]+):?([A-Za-z0-9\-\_\/\:]*)?}")
32
+ re_pattern: re.Pattern[str] = re.compile(r"\${([A-Za-z0-9\-\_]+):?([A-Za-z0-9\-\_\/\:\.]*)?}")
33
33
 
34
34
  def __init__(
35
35
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastapi_factory_utilities
3
- Version: 0.2.1
3
+ Version: 0.2.3
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
  Keywords: python,fastapi,beanie,httpx,opentelemetry,microservices
@@ -7,7 +7,7 @@ fastapi_factory_utilities/core/api/v1/sys/health.py,sha256=IF51Z1seOFn91m3FC57U8
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=I04abOkkWiY9ChgkUNeiwnuWq8kkBoRAtMLBUKB7J7Y,405
9
9
  fastapi_factory_utilities/core/app/application.py,sha256=XdfQRG8IwyukEYXNF6i2s3qq0eAo1_XG9Xa9yV7zKf8,4975
10
- fastapi_factory_utilities/core/app/builder.py,sha256=aPmtnGPAsCF4vGIlqSLKWW5XW7JF3nBN7bfk_zudR28,4374
10
+ fastapi_factory_utilities/core/app/builder.py,sha256=VbThqoI1qWnADwPQ61D774oNZ5d6OMxW0tyXr_Yz5E4,4503
11
11
  fastapi_factory_utilities/core/app/config.py,sha256=7ELIoCy1AGCD4Zq7O-jZk6VJcqDU8H-00CSrvtwzdZE,6466
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
@@ -19,9 +19,9 @@ fastapi_factory_utilities/core/exceptions.py,sha256=7ntbaMptYn5OOPeKPVR4zU98NIC0
19
19
  fastapi_factory_utilities/core/plugins/__init__.py,sha256=W-BCkqP0xG980980z3mc8T6Vrp1Akv4szA0PRzkUbiU,756
20
20
  fastapi_factory_utilities/core/plugins/example/__init__.py,sha256=GF69IygLXxzrCh7VryekEWun663kKBhWtRS3w-1tzBc,1030
21
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
22
+ fastapi_factory_utilities/core/plugins/odm_plugin/__init__.py,sha256=DwtLFB291G7GQDV8yh_dN7aXPMy6HWvDEh8PbWhbVDA,5316
23
+ fastapi_factory_utilities/core/plugins/odm_plugin/builder.py,sha256=3B5EgY8deS_dr9NYZbeJq9cibPs65kN0Ogg-1yecF3s,8547
24
+ fastapi_factory_utilities/core/plugins/odm_plugin/configs.py,sha256=zQoJC1wLNyq2pZyFhl0bKeNsTl4y_4_82BHCCaOEjCQ,331
25
25
  fastapi_factory_utilities/core/plugins/odm_plugin/depends.py,sha256=OcLsfTLzMBk_xFV6qsMy_-qFkiphEbbEuaHUooagxg8,730
26
26
  fastapi_factory_utilities/core/plugins/odm_plugin/documents.py,sha256=ENEB-Lm3T7_tN1xuIYPsUh8fpWj4aqh0xmrZt6vJCK0,1075
27
27
  fastapi_factory_utilities/core/plugins/odm_plugin/exceptions.py,sha256=acnKJB0lGAzDs-7-LjBap8shjP3iV1a7dw7ouPVF27o,551
@@ -43,8 +43,8 @@ fastapi_factory_utilities/core/utils/configs.py,sha256=qM0pCrsK8ZyfCoyova_VrhR4e
43
43
  fastapi_factory_utilities/core/utils/importlib.py,sha256=DYcPo7K0s95WV5xxtucpufWsTj8Pxv25sWunDmmNUYI,797
44
44
  fastapi_factory_utilities/core/utils/log.py,sha256=6V9CL3bQio4e47YxcSXM2JQRGhVxuBfmcEbcF4RtCfQ,6393
45
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
46
+ fastapi_factory_utilities/core/utils/uvicorn.py,sha256=XThylG-nOPVL00w6MIWGODnweoM7VxmpSFcyoPcmqns,2609
47
+ fastapi_factory_utilities/core/utils/yaml_reader.py,sha256=KNlwHvpraAp04JjeXSSk72BLuILH3lhEKrmRaUUgo2k,6103
48
48
  fastapi_factory_utilities/example/__init__.py,sha256=LEKnPTBcgDyfHeOjlVxjK5lFdFqS-7-mHDuVuM2Jh_Y,206
49
49
  fastapi_factory_utilities/example/__main__.py,sha256=Iwp_6rK7Lcv2F-XAKn6xjxQHOWjx2OjgwKAr91tfUfk,135
50
50
  fastapi_factory_utilities/example/api/__init__.py,sha256=qI82eeSwVjR6jSkX1pxm8ALv9WPQ_iHurFY4G2K7VzE,554
@@ -64,8 +64,8 @@ fastapi_factory_utilities/example/models/books/repository.py,sha256=7K63uAsSEGZ2
64
64
  fastapi_factory_utilities/example/services/books/__init__.py,sha256=Z06yNRoA7Zg3TGN-Q9rrvJg6Bbx-qJw661MVwukV6vQ,148
65
65
  fastapi_factory_utilities/example/services/books/services.py,sha256=-x7d4hotUWLzWo5uImMjFmtNcSTHwWv2bfttIbYYKbA,5380
66
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,,
67
+ fastapi_factory_utilities-0.2.3.dist-info/LICENSE,sha256=iO1nLzMMst6vEiqgSUrfrbetM7b0bvdzXhbed5tqG8o,1074
68
+ fastapi_factory_utilities-0.2.3.dist-info/METADATA,sha256=T3Kpr1rWSa-cgNdz1wOHw4kyhI4cj3bF4McC9XTE0fk,3314
69
+ fastapi_factory_utilities-0.2.3.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
70
+ fastapi_factory_utilities-0.2.3.dist-info/entry_points.txt,sha256=IK0VcBexXo4uXQmTrbfhhnnfq4GmXPRn0GBB8hzlsq4,101
71
+ fastapi_factory_utilities-0.2.3.dist-info/RECORD,,