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

@@ -82,6 +82,8 @@ class DependencyConfig(BaseModel):
82
82
  """Dependency config."""
83
83
 
84
84
  kratos: HttpServiceDependencyConfig | None = Field(default=None, description="Kratos dependency config")
85
+ hydra_admin: HttpServiceDependencyConfig | None = Field(default=None, description="Hydra admin dependency config")
86
+ hydra_public: HttpServiceDependencyConfig | None = Field(default=None, description="Hydra public dependency config")
85
87
 
86
88
 
87
89
  class RootConfig(BaseModel):
@@ -77,7 +77,8 @@ class FastAPIBuilder:
77
77
 
78
78
  for middleware_args in self._middleware_list:
79
79
  fastapi.add_middleware(
80
- middleware_class=middleware_args.middleware_class, **middleware_args.kwargs # type: ignore
80
+ middleware_class=middleware_args.middleware_class,
81
+ **middleware_args.kwargs, # type: ignore
81
82
  )
82
83
 
83
84
  fastapi.include_router(router=self._base_router)
@@ -67,7 +67,6 @@ class PluginManager:
67
67
  plugins: list[PluginProtocol] = []
68
68
 
69
69
  for plugin_enum in want_to_activate_plugins:
70
-
71
70
  try:
72
71
  # Using a custom import function to be able to mock it in the tests.
73
72
  plugin_module: ModuleType = cls._import_module(name=plugin_enum.value, package=plugin_package)
@@ -268,6 +268,7 @@ class AbstractRepository(ABC, Generic[DocumentGenericType, EntityGenericType]):
268
268
  lazy_parse=lazy_parse,
269
269
  nesting_depth=nesting_depth,
270
270
  nesting_depths_per_field=nesting_depths_per_field,
271
+ **pymongo_kwargs,
271
272
  ).to_list()
272
273
  except PyMongoError as error:
273
274
  raise OperationError(f"Failed to find documents: {error}") from error
@@ -140,11 +140,12 @@ 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
- jwt_raw: str = (
144
- self.jwt_raw
145
- if self.jwt_raw is not None
146
- else self._extract_raw_token(request=request) # type: ignore[arg-type]
147
- )
143
+
144
+ if self.jwt_raw is None:
145
+ jwt_raw: str = self._extract_raw_token(request=request) # type: ignore[arg-type]
146
+ else:
147
+ jwt_raw: str = self.jwt_raw
148
+
148
149
  # Execute the io bound and cpu bound tasks in parallel
149
150
  async with TaskGroup() as tg:
150
151
  # TODO: Can be disabled by configuration (for operation purposes)
@@ -0,0 +1,13 @@
1
+ """Hydra service module."""
2
+
3
+ from .exceptions import HydraOperationError, HydraTokenInvalidError
4
+ from .objects import HydraTokenIntrospectObject
5
+ from .services import HydraService, depends_hydra_service
6
+
7
+ __all__: list[str] = [
8
+ "HydraOperationError",
9
+ "HydraService",
10
+ "HydraTokenIntrospectObject",
11
+ "HydraTokenInvalidError",
12
+ "depends_hydra_service",
13
+ ]
@@ -0,0 +1,15 @@
1
+ """Python exceptions for the Hydra service."""
2
+
3
+ from fastapi_factory_utilities.core.exceptions import FastAPIFactoryUtilitiesError
4
+
5
+
6
+ class HydraError(FastAPIFactoryUtilitiesError):
7
+ """Base class for all exceptions raised by the Hydra service."""
8
+
9
+
10
+ class HydraOperationError(HydraError):
11
+ """Exception raised when a Hydra operation fails."""
12
+
13
+
14
+ class HydraTokenInvalidError(HydraError):
15
+ """Exception raised when a Hydra token is invalid."""
@@ -0,0 +1,26 @@
1
+ """Provides the objects for the Hydra service."""
2
+
3
+ from typing import ClassVar
4
+
5
+ from pydantic import BaseModel, ConfigDict
6
+
7
+
8
+ class HydraTokenIntrospectObject(BaseModel):
9
+ """Represents the object returned by the Hydra token introspection."""
10
+
11
+ model_config: ClassVar[ConfigDict] = ConfigDict(extra="ignore")
12
+
13
+ active: bool
14
+ aud: list[str]
15
+ client_id: str
16
+ exp: int
17
+ ext: dict[str, str] | None = None
18
+ iat: int
19
+ iss: str
20
+ nbf: int
21
+ obfuscated_subject: str | None = None
22
+ scope: str
23
+ sub: str
24
+ token_type: str
25
+ token_use: str
26
+ username: str | None = None
@@ -0,0 +1,122 @@
1
+ """Provides a service to interact with the Hydra service."""
2
+
3
+ from base64 import b64encode
4
+ from http import HTTPStatus
5
+ from typing import Annotated
6
+
7
+ import aiohttp
8
+ from fastapi import Depends
9
+ from pydantic import ValidationError
10
+
11
+ from fastapi_factory_utilities.core.app import (
12
+ DependencyConfig,
13
+ HttpServiceDependencyConfig,
14
+ depends_dependency_config,
15
+ )
16
+
17
+ from .exceptions import HydraOperationError, HydraTokenInvalidError
18
+ from .objects import HydraTokenIntrospectObject
19
+
20
+
21
+ class HydraService:
22
+ """Service to interact with the Hydra service."""
23
+
24
+ INTROSPECT_ENDPOINT: str = "/admin/oauth2/introspect"
25
+ CLIENT_CREDENTIALS_ENDPOINT: str = "/oauth2/token"
26
+
27
+ def __init__(
28
+ self,
29
+ hydra_admin_http_config: HttpServiceDependencyConfig,
30
+ hydra_public_http_config: HttpServiceDependencyConfig,
31
+ ) -> None:
32
+ """Instanciate the Hydra service.
33
+
34
+ Args:
35
+ hydra_admin_http_config (HttpServiceDependencyConfig): The Hydra admin HTTP configuration.
36
+ hydra_public_http_config (HttpServiceDependencyConfig): The Hydra public HTTP configuration.
37
+ """
38
+ self._hydra_admin_http_config: HttpServiceDependencyConfig = hydra_admin_http_config
39
+ self._hydra_public_http_config: HttpServiceDependencyConfig = hydra_public_http_config
40
+
41
+ async def introspect(self, token: str) -> HydraTokenIntrospectObject:
42
+ """Introspects a token using the Hydra service.
43
+
44
+ Args:
45
+ token (str): The token to introspect.
46
+
47
+ Raises:
48
+ HydraOperationError: If the introspection fails.
49
+ HydraTokenInvalidError: If the token is invalid.
50
+ """
51
+ async with aiohttp.ClientSession(
52
+ base_url=str(self._hydra_admin_http_config.url),
53
+ ) as session:
54
+ async with session.post(
55
+ url=self.INTROSPECT_ENDPOINT,
56
+ data={"token": token},
57
+ ) as response:
58
+ if response.status != HTTPStatus.OK:
59
+ raise HydraTokenInvalidError()
60
+
61
+ try:
62
+ instrospect: HydraTokenIntrospectObject = HydraTokenIntrospectObject(**await response.json())
63
+ except ValidationError as error:
64
+ raise HydraOperationError() from error
65
+
66
+ return instrospect
67
+
68
+ async def oauth2_client_credentials(self, client_id: str, client_secret: str, scope: str) -> str:
69
+ """Get the OAuth2 client credentials.
70
+
71
+ Args:
72
+ client_id (str): The client ID.
73
+ client_secret (str): The client secret.
74
+ scope (str): The scope.
75
+
76
+ Returns:
77
+ str: The access token.
78
+
79
+ Raises:
80
+ HydraOperationError: If the client credentials request fails.
81
+ """
82
+ # Create base64 encoded Basic Auth header
83
+ auth_string = f"{client_id}:{client_secret}"
84
+ auth_bytes = auth_string.encode("utf-8")
85
+ auth_b64 = b64encode(auth_bytes).decode("utf-8")
86
+
87
+ async with aiohttp.ClientSession(
88
+ base_url=str(self._hydra_public_http_config.url),
89
+ ) as session:
90
+ async with session.post(
91
+ url=self.CLIENT_CREDENTIALS_ENDPOINT,
92
+ headers={"Authorization": f"Basic {auth_b64}"},
93
+ data={"grant_type": "client_credentials", "scope": scope},
94
+ ) as response:
95
+ response_data = await response.json()
96
+ if response.status != HTTPStatus.OK:
97
+ raise HydraOperationError(f"Failed to get client credentials: {response_data}")
98
+
99
+ return response_data["access_token"]
100
+
101
+
102
+ def depends_hydra_service(
103
+ dependency_config: Annotated[DependencyConfig, Depends(depends_dependency_config)],
104
+ ) -> HydraService:
105
+ """Dependency injection for the Hydra service.
106
+
107
+ Args:
108
+ dependency_config (DependencyConfig): The dependency configuration.
109
+
110
+ Returns:
111
+ HydraService: The Hydra service instance.
112
+
113
+ Raises:
114
+ HydraOperationError: If the Hydra admin or public dependency is not configured.
115
+ """
116
+ if dependency_config.hydra_admin is None or dependency_config.hydra_public is None:
117
+ raise HydraOperationError(message="Hydra admin or public dependency not configured")
118
+
119
+ return HydraService(
120
+ hydra_admin_http_config=dependency_config.hydra_admin,
121
+ hydra_public_http_config=dependency_config.hydra_public,
122
+ )
@@ -3,6 +3,7 @@
3
3
  ```python
4
4
  # Example of using the MonitoredAbstract
5
5
 
6
+
6
7
  class MyMonitored(MonitoredAbstract):
7
8
  def __init__(self, status_service: StatusService) -> None:
8
9
  super().__init__(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastapi_factory_utilities
3
- Version: 0.3.10
3
+ Version: 0.4.1
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
@@ -31,7 +31,7 @@ Requires-Dist: opentelemetry-sdk (>=1.26.0,<2.0.0)
31
31
  Requires-Dist: pyaml (>=25.1.0,<26.0.0)
32
32
  Requires-Dist: pydantic (>=2.8.2,<3.0.0)
33
33
  Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
34
- Requires-Dist: pymongo (>=4.9.2,<4.10.0)
34
+ Requires-Dist: pymongo (>=4.9.2,<4.14.0)
35
35
  Requires-Dist: reactivex (>=4.0.4,<5.0.0)
36
36
  Requires-Dist: structlog (>=24.1,<26.0)
37
37
  Requires-Dist: typer (>=0,<1)
@@ -8,13 +8,13 @@ fastapi_factory_utilities/core/api/v1/sys/readiness.py,sha256=xIY8pQLShU7KWRtlOU
8
8
  fastapi_factory_utilities/core/app/__init__.py,sha256=IHHkcu3t-fX8vxQk12A36cE-yTjGn_PInDpL_OlRSE8,596
9
9
  fastapi_factory_utilities/core/app/application.py,sha256=WrDXh00r_jzQTtZGeFO43lIzvDraplitejTaSJj_uFE,5091
10
10
  fastapi_factory_utilities/core/app/builder.py,sha256=XKtJuRxvaqzNdhfNXGkyyxEH4MkZCgAUjkqYnOws8n0,4728
11
- fastapi_factory_utilities/core/app/config.py,sha256=81KYoxB14TX05jMWujPNjLI1BXkvMnUyw2VgF7nJIE0,7063
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=DgIqiCnJK6cqsG-sg4H7Pi0lkhaxOhSLQt_ksHjpjW0,2835
14
+ fastapi_factory_utilities/core/app/fastapi_builder.py,sha256=KoywPbWu9wY5s1KpBAwxgqH07PYT3Y6Mtlq-PP4__5I,2852
15
15
  fastapi_factory_utilities/core/app/plugin_manager/__init__.py,sha256=eMfxCsk41Caw_juAawmDZHhytNI_ubXmqfRDug2AzvQ,319
16
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
17
+ fastapi_factory_utilities/core/app/plugin_manager/plugin_manager.py,sha256=b6wDStsjAdCKExFFNCFEmeMERNsVCeIp1qseKfn5TO4,6681
18
18
  fastapi_factory_utilities/core/exceptions.py,sha256=HAd0RDJNBVc1NOcwfHQo_Xya8SCYuD9edynx3VKMYVs,1784
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
@@ -25,15 +25,19 @@ fastapi_factory_utilities/core/plugins/odm_plugin/configs.py,sha256=zQoJC1wLNyq2
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=BFQYHxHBmTacJRfhZi2OffvT_RAFvAAiDVQAa_d6Y7w,1141
27
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=pOOADEe8mz6FuZkNzV46H8RNvi77FojJqb3bz9RQapo,11279
28
+ fastapi_factory_utilities/core/plugins/odm_plugin/repositories.py,sha256=GJ3ovlxzTpiJ2_XlgARtwn6j0SbQxxAray_r8QWvGok,11313
29
29
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/__init__.py,sha256=4mq4a6U_nRxe3VxpHnC0FhRh0hpKO8l6QSUE7AazeBw,4689
30
30
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/builder.py,sha256=9npQImifYAbEg0lFG7KwZ8V78SNrPoaINgd8vKitdMw,12509
31
31
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/configs.py,sha256=pMG9leMB7rtdkdGFLIxXflV7bf9epGrrYPt2N97KZcM,3750
32
32
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/exceptions.py,sha256=CpsHayfQpP0zghN8y5PP6TBy-cXhHoNxBR--I86gAdE,327
33
33
  fastapi_factory_utilities/core/plugins/opentelemetry_plugin/helpers.py,sha256=qpTIzX67orJz7vy6SBIwRs24omMBoToJkhpurZRjPuk,1533
34
34
  fastapi_factory_utilities/core/protocols.py,sha256=TzZKr_KfmTphk2LL-TD2XzxNlLbihbGM2DxWMhc5lEQ,2428
35
- fastapi_factory_utilities/core/security/jwt.py,sha256=LuNVmTlONrmoKl7ghNv5JHV4qzMNOwuxJQlWgGSvBoo,5631
35
+ fastapi_factory_utilities/core/security/jwt.py,sha256=jO3FNOiqVvCCbvShUmCyfii8oLXNbYk_Sfsb_O29dng,5630
36
36
  fastapi_factory_utilities/core/security/kratos.py,sha256=yP9-TkELeXRPRYE9aQRlOPlwvaUJ7VQpyAea8ucWUfg,3364
37
+ fastapi_factory_utilities/core/services/hydra/__init__.py,sha256=AKBYNc3zW5OsCLLeFSXqmDbWbQefHUJxstLpsXLQEUQ,369
38
+ fastapi_factory_utilities/core/services/hydra/exceptions.py,sha256=ePMrfZturU2IVcxOebR0CbVKKqprce_fK-4UXbPPgNI,450
39
+ fastapi_factory_utilities/core/services/hydra/objects.py,sha256=2CeV_4zmwwpfbXQ0TM9B_UnNkZuIRXweFP_VALBo57c,601
40
+ fastapi_factory_utilities/core/services/hydra/services.py,sha256=Urc98pM23OatHr_WdgrpK1U4E2qsjF1fpXo0xnNjZ60,4411
37
41
  fastapi_factory_utilities/core/services/kratos/__init__.py,sha256=DaC29-Ol0WR5vX56IHLGDXP9UrhISq0Juhg_sJTasw4,368
38
42
  fastapi_factory_utilities/core/services/kratos/enums.py,sha256=ULJppowlZbOjdnUIXQyI4_nHmHZoNnv7-M1CYQBYXFY,220
39
43
  fastapi_factory_utilities/core/services/kratos/exceptions.py,sha256=xAX01-lQvPpADgcwhB5YWSy1UqAxG38s2rlU9AJBJd8,472
@@ -49,7 +53,7 @@ fastapi_factory_utilities/core/services/status/types.py,sha256=GJOGRra6NtpUS4q1c
49
53
  fastapi_factory_utilities/core/utils/configs.py,sha256=qM0pCrsK8ZyfCoyova_VrhR4eUX3LSPCbWunGMWcSVg,2581
50
54
  fastapi_factory_utilities/core/utils/importlib.py,sha256=DYcPo7K0s95WV5xxtucpufWsTj8Pxv25sWunDmmNUYI,797
51
55
  fastapi_factory_utilities/core/utils/log.py,sha256=6V9CL3bQio4e47YxcSXM2JQRGhVxuBfmcEbcF4RtCfQ,6393
52
- fastapi_factory_utilities/core/utils/status.py,sha256=1zxur98Wfum3JzpuzoAPoRIwQmXhFsTS2oxgbn5uFfg,1933
56
+ fastapi_factory_utilities/core/utils/status.py,sha256=kOUX96D0IeOO8YOk2QTDF1_5rH69_93BSmxerjmrhwk,1934
53
57
  fastapi_factory_utilities/core/utils/uvicorn.py,sha256=XThylG-nOPVL00w6MIWGODnweoM7VxmpSFcyoPcmqns,2609
54
58
  fastapi_factory_utilities/core/utils/yaml_reader.py,sha256=KNlwHvpraAp04JjeXSSk72BLuILH3lhEKrmRaUUgo2k,6103
55
59
  fastapi_factory_utilities/example/__init__.py,sha256=LEKnPTBcgDyfHeOjlVxjK5lFdFqS-7-mHDuVuM2Jh_Y,206
@@ -71,8 +75,8 @@ fastapi_factory_utilities/example/models/books/repository.py,sha256=7K63uAsSEGZ2
71
75
  fastapi_factory_utilities/example/services/books/__init__.py,sha256=Z06yNRoA7Zg3TGN-Q9rrvJg6Bbx-qJw661MVwukV6vQ,148
72
76
  fastapi_factory_utilities/example/services/books/services.py,sha256=-x7d4hotUWLzWo5uImMjFmtNcSTHwWv2bfttIbYYKbA,5380
73
77
  fastapi_factory_utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
- fastapi_factory_utilities-0.3.10.dist-info/LICENSE,sha256=iO1nLzMMst6vEiqgSUrfrbetM7b0bvdzXhbed5tqG8o,1074
75
- fastapi_factory_utilities-0.3.10.dist-info/METADATA,sha256=qDMLKgH6OIqvbg5cR6jErThx-6F66YbdkGrwiUzqufM,3479
76
- fastapi_factory_utilities-0.3.10.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
77
- fastapi_factory_utilities-0.3.10.dist-info/entry_points.txt,sha256=IK0VcBexXo4uXQmTrbfhhnnfq4GmXPRn0GBB8hzlsq4,101
78
- fastapi_factory_utilities-0.3.10.dist-info/RECORD,,
78
+ fastapi_factory_utilities-0.4.1.dist-info/LICENSE,sha256=iO1nLzMMst6vEiqgSUrfrbetM7b0bvdzXhbed5tqG8o,1074
79
+ fastapi_factory_utilities-0.4.1.dist-info/METADATA,sha256=mFUKdMVor7-1TzUxjzALV4JW6MWFUJy9zEo3KdiJlQw,3478
80
+ fastapi_factory_utilities-0.4.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
81
+ fastapi_factory_utilities-0.4.1.dist-info/entry_points.txt,sha256=IK0VcBexXo4uXQmTrbfhhnnfq4GmXPRn0GBB8hzlsq4,101
82
+ fastapi_factory_utilities-0.4.1.dist-info/RECORD,,