jararaca 0.3.11a16__py3-none-any.whl → 0.4.0a5__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.
- README.md +121 -0
- jararaca/__init__.py +184 -12
- jararaca/__main__.py +4 -0
- jararaca/broker_backend/__init__.py +4 -0
- jararaca/broker_backend/mapper.py +4 -0
- jararaca/broker_backend/redis_broker_backend.py +9 -3
- jararaca/cli.py +272 -47
- jararaca/common/__init__.py +3 -0
- jararaca/core/__init__.py +3 -0
- jararaca/core/providers.py +4 -0
- jararaca/core/uow.py +41 -7
- jararaca/di.py +4 -0
- jararaca/files/entity.py.mako +4 -0
- jararaca/lifecycle.py +6 -2
- jararaca/messagebus/__init__.py +4 -0
- jararaca/messagebus/bus_message_controller.py +4 -0
- jararaca/messagebus/consumers/__init__.py +3 -0
- jararaca/messagebus/decorators.py +33 -67
- jararaca/messagebus/implicit_headers.py +49 -0
- jararaca/messagebus/interceptors/__init__.py +3 -0
- jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +13 -4
- jararaca/messagebus/interceptors/publisher_interceptor.py +4 -0
- jararaca/messagebus/message.py +4 -0
- jararaca/messagebus/publisher.py +6 -0
- jararaca/messagebus/worker.py +850 -383
- jararaca/microservice.py +110 -1
- jararaca/observability/constants.py +7 -0
- jararaca/observability/decorators.py +170 -13
- jararaca/observability/fastapi_exception_handler.py +37 -0
- jararaca/observability/hooks.py +109 -0
- jararaca/observability/interceptor.py +4 -0
- jararaca/observability/providers/__init__.py +3 -0
- jararaca/observability/providers/otel.py +202 -11
- jararaca/persistence/base.py +38 -2
- jararaca/persistence/exports.py +4 -0
- jararaca/persistence/interceptors/__init__.py +3 -0
- jararaca/persistence/interceptors/aiosqa_interceptor.py +86 -73
- jararaca/persistence/interceptors/constants.py +5 -0
- jararaca/persistence/interceptors/decorators.py +50 -0
- jararaca/persistence/session.py +3 -0
- jararaca/persistence/sort_filter.py +4 -0
- jararaca/persistence/utilities.py +50 -20
- jararaca/presentation/__init__.py +3 -0
- jararaca/presentation/decorators.py +88 -86
- jararaca/presentation/exceptions.py +23 -0
- jararaca/presentation/hooks.py +4 -0
- jararaca/presentation/http_microservice.py +4 -0
- jararaca/presentation/server.py +97 -45
- jararaca/presentation/websocket/__init__.py +3 -0
- jararaca/presentation/websocket/base_types.py +4 -0
- jararaca/presentation/websocket/context.py +4 -0
- jararaca/presentation/websocket/decorators.py +8 -41
- jararaca/presentation/websocket/redis.py +280 -53
- jararaca/presentation/websocket/types.py +4 -0
- jararaca/presentation/websocket/websocket_interceptor.py +46 -19
- jararaca/reflect/__init__.py +3 -0
- jararaca/reflect/controller_inspect.py +16 -10
- jararaca/reflect/decorators.py +238 -0
- jararaca/reflect/metadata.py +34 -25
- jararaca/rpc/__init__.py +3 -0
- jararaca/rpc/http/__init__.py +101 -0
- jararaca/rpc/http/backends/__init__.py +14 -0
- jararaca/rpc/http/backends/httpx.py +43 -9
- jararaca/rpc/http/backends/otel.py +4 -0
- jararaca/rpc/http/decorators.py +378 -113
- jararaca/rpc/http/httpx.py +3 -0
- jararaca/scheduler/__init__.py +3 -0
- jararaca/scheduler/beat_worker.py +521 -105
- jararaca/scheduler/decorators.py +15 -22
- jararaca/scheduler/types.py +4 -0
- jararaca/tools/app_config/__init__.py +3 -0
- jararaca/tools/app_config/decorators.py +7 -19
- jararaca/tools/app_config/interceptor.py +6 -2
- jararaca/tools/typescript/__init__.py +3 -0
- jararaca/tools/typescript/decorators.py +120 -0
- jararaca/tools/typescript/interface_parser.py +1074 -173
- jararaca/utils/__init__.py +3 -0
- jararaca/utils/rabbitmq_utils.py +65 -39
- jararaca/utils/retry.py +10 -3
- jararaca-0.4.0a5.dist-info/LICENSE +674 -0
- jararaca-0.4.0a5.dist-info/LICENSES/GPL-3.0-or-later.txt +232 -0
- {jararaca-0.3.11a16.dist-info → jararaca-0.4.0a5.dist-info}/METADATA +11 -7
- jararaca-0.4.0a5.dist-info/RECORD +88 -0
- {jararaca-0.3.11a16.dist-info → jararaca-0.4.0a5.dist-info}/WHEEL +1 -1
- pyproject.toml +131 -0
- jararaca-0.3.11a16.dist-info/RECORD +0 -74
- /jararaca-0.3.11a16.dist-info/LICENSE → /LICENSE +0 -0
- {jararaca-0.3.11a16.dist-info → jararaca-0.4.0a5.dist-info}/entry_points.txt +0 -0
jararaca/scheduler/decorators.py
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Lucas S
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
1
5
|
import inspect
|
|
2
6
|
from dataclasses import dataclass
|
|
3
|
-
from
|
|
7
|
+
from types import FunctionType
|
|
8
|
+
from typing import Any, Awaitable, Callable, TypeVar
|
|
4
9
|
|
|
5
10
|
from jararaca.reflect.controller_inspect import (
|
|
6
11
|
ControllerMemberReflect,
|
|
7
12
|
inspect_controller,
|
|
8
13
|
)
|
|
14
|
+
from jararaca.reflect.decorators import StackableDecorator
|
|
9
15
|
|
|
10
16
|
DECORATED_FUNC = TypeVar("DECORATED_FUNC", bound=Callable[..., Any])
|
|
11
17
|
|
|
12
18
|
|
|
13
|
-
class ScheduledAction:
|
|
14
|
-
SCHEDULED_ACTION_ATTR = "__scheduled_action__"
|
|
19
|
+
class ScheduledAction(StackableDecorator):
|
|
15
20
|
|
|
16
21
|
def __init__(
|
|
17
22
|
self,
|
|
@@ -62,23 +67,6 @@ class ScheduledAction:
|
|
|
62
67
|
An optional name for the scheduled action, used for filtering which actions to run.
|
|
63
68
|
"""
|
|
64
69
|
|
|
65
|
-
def __call__(self, func: DECORATED_FUNC) -> DECORATED_FUNC:
|
|
66
|
-
ScheduledAction.register(func, self)
|
|
67
|
-
return func
|
|
68
|
-
|
|
69
|
-
@staticmethod
|
|
70
|
-
def register(func: DECORATED_FUNC, scheduled_action: "ScheduledAction") -> None:
|
|
71
|
-
setattr(func, ScheduledAction.SCHEDULED_ACTION_ATTR, scheduled_action)
|
|
72
|
-
|
|
73
|
-
@staticmethod
|
|
74
|
-
def get_scheduled_action(func: DECORATED_FUNC) -> "ScheduledAction | None":
|
|
75
|
-
if not hasattr(func, ScheduledAction.SCHEDULED_ACTION_ATTR):
|
|
76
|
-
return None
|
|
77
|
-
|
|
78
|
-
return cast(
|
|
79
|
-
ScheduledAction, getattr(func, ScheduledAction.SCHEDULED_ACTION_ATTR)
|
|
80
|
-
)
|
|
81
|
-
|
|
82
70
|
@staticmethod
|
|
83
71
|
def get_function_id(
|
|
84
72
|
func: Callable[..., Any],
|
|
@@ -103,12 +91,17 @@ def get_type_scheduled_actions(
|
|
|
103
91
|
|
|
104
92
|
_, member_metadata_map = inspect_controller(instance.__class__)
|
|
105
93
|
|
|
106
|
-
members
|
|
94
|
+
members: list[tuple[str, FunctionType]] = []
|
|
95
|
+
for name, value in inspect.getmembers_static(
|
|
96
|
+
instance, predicate=inspect.isfunction
|
|
97
|
+
):
|
|
98
|
+
|
|
99
|
+
members.append((name, value))
|
|
107
100
|
|
|
108
101
|
scheduled_actions: list[ScheduledActionData] = []
|
|
109
102
|
|
|
110
103
|
for name, member in members:
|
|
111
|
-
scheduled_action = ScheduledAction.
|
|
104
|
+
scheduled_action = ScheduledAction.get_last(member)
|
|
112
105
|
|
|
113
106
|
if scheduled_action is None:
|
|
114
107
|
continue
|
jararaca/scheduler/types.py
CHANGED
|
@@ -1,31 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Lucas S
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
from typing import Any, Type, TypeVar
|
|
2
6
|
|
|
3
7
|
from pydantic import BaseModel
|
|
4
8
|
|
|
5
9
|
from jararaca.core.providers import Token
|
|
10
|
+
from jararaca.reflect.decorators import StackableDecorator
|
|
6
11
|
|
|
7
12
|
DECORATED_CLASS = TypeVar("DECORATED_CLASS", bound=Any)
|
|
8
13
|
|
|
9
14
|
|
|
10
|
-
class RequiresConfig:
|
|
11
|
-
|
|
12
|
-
REQUIRE_CONFIG_ATTR = "__requires_config__"
|
|
15
|
+
class RequiresConfig(StackableDecorator):
|
|
13
16
|
|
|
14
17
|
def __init__(self, token: Token[Any], config: Type[BaseModel]):
|
|
15
18
|
self.config = config
|
|
16
19
|
self.token = token
|
|
17
|
-
|
|
18
|
-
@staticmethod
|
|
19
|
-
def register(cls: Type[DECORATED_CLASS], config: "RequiresConfig") -> None:
|
|
20
|
-
setattr(cls, RequiresConfig.REQUIRE_CONFIG_ATTR, config)
|
|
21
|
-
|
|
22
|
-
@staticmethod
|
|
23
|
-
def get(cls: Type[DECORATED_CLASS]) -> "RequiresConfig | None":
|
|
24
|
-
if not hasattr(cls, RequiresConfig.REQUIRE_CONFIG_ATTR):
|
|
25
|
-
return None
|
|
26
|
-
|
|
27
|
-
return cast(RequiresConfig, getattr(cls, RequiresConfig.REQUIRE_CONFIG_ATTR))
|
|
28
|
-
|
|
29
|
-
def __call__(self, cls: Type[DECORATED_CLASS]) -> Type[DECORATED_CLASS]:
|
|
30
|
-
RequiresConfig.register(cls, self)
|
|
31
|
-
return cls
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Lucas S
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
1
5
|
import logging
|
|
2
6
|
import os
|
|
3
7
|
from contextlib import asynccontextmanager
|
|
@@ -56,7 +60,7 @@ class AppConfigurationInterceptor(AppInterceptor, AppInterceptorWithLifecycle):
|
|
|
56
60
|
*[
|
|
57
61
|
(config.token, config.config)
|
|
58
62
|
for controller in app.controllers
|
|
59
|
-
if (config := RequiresConfig.
|
|
63
|
+
if (config := RequiresConfig.get_last(controller))
|
|
60
64
|
],
|
|
61
65
|
]
|
|
62
66
|
|
|
@@ -90,7 +94,7 @@ class AppConfigurationInterceptor(AppInterceptor, AppInterceptorWithLifecycle):
|
|
|
90
94
|
|
|
91
95
|
yield
|
|
92
96
|
|
|
93
|
-
logger.
|
|
97
|
+
logger.debug("finalizando")
|
|
94
98
|
|
|
95
99
|
|
|
96
100
|
class AppConfigValidationError(Exception):
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Lucas S
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
from typing import Any, Callable, TypeVar
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from jararaca.reflect.decorators import StackableDecorator
|
|
10
|
+
|
|
11
|
+
DECORATED_FUNC = TypeVar("DECORATED_FUNC", bound=Callable[..., Any])
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class QueryEndpoint(StackableDecorator):
|
|
15
|
+
"""
|
|
16
|
+
Decorator to mark a endpoint function as a query endpoint for Typescript generation.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, has_infinite_query: bool = False) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initialize the QueryEndpoint decorator.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
has_infinite_query: Whether the query endpoint supports infinite queries.
|
|
25
|
+
Important:
|
|
26
|
+
- Make sure a PaginatedQuery child instance is on the first argument
|
|
27
|
+
- Make sure the endpoint is a Patch (recommended) or Put method
|
|
28
|
+
- Make sure the endpoint returns a Paginated[T]
|
|
29
|
+
"""
|
|
30
|
+
self.has_infinite_query = has_infinite_query
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def extract_query_endpoint(func: Any) -> "QueryEndpoint | None":
|
|
34
|
+
"""
|
|
35
|
+
Check if the function is marked as a query endpoint.
|
|
36
|
+
"""
|
|
37
|
+
return QueryEndpoint.get_last(func)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MutationEndpoint(StackableDecorator):
|
|
41
|
+
"""
|
|
42
|
+
Decorator to mark a endpoint function as a mutation endpoint for Typescript generation.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self) -> None: ...
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def is_mutation(func: Any) -> bool:
|
|
49
|
+
"""
|
|
50
|
+
Check if the function is marked as a mutation endpoint.
|
|
51
|
+
"""
|
|
52
|
+
return MutationEndpoint.get_last(func) is not None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
BASEMODEL_T = TypeVar("BASEMODEL_T", bound=BaseModel)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class SplitInputOutput(StackableDecorator):
|
|
59
|
+
"""
|
|
60
|
+
Decorator to mark a Pydantic model to generate separate Input and Output TypeScript interfaces.
|
|
61
|
+
|
|
62
|
+
Input interface: Used for API inputs (mutations/queries), handles optional fields with defaults
|
|
63
|
+
Output interface: Used for API outputs, represents the complete object structure
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self) -> None:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def is_split_model(cls: type) -> bool:
|
|
71
|
+
"""
|
|
72
|
+
Check if the Pydantic model is marked for split interface generation.
|
|
73
|
+
"""
|
|
74
|
+
return SplitInputOutput.get_last(cls) is not None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ExposeType:
|
|
78
|
+
"""
|
|
79
|
+
Decorator to explicitly expose types for TypeScript interface generation.
|
|
80
|
+
|
|
81
|
+
Use this decorator to include types in the generated TypeScript output without
|
|
82
|
+
needing them as request/response bodies or indirect dependencies.
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
@ExposeType()
|
|
86
|
+
class UserRole(BaseModel):
|
|
87
|
+
id: str
|
|
88
|
+
name: str
|
|
89
|
+
|
|
90
|
+
# This ensures UserRole interface is generated even if it's not
|
|
91
|
+
# directly referenced in any REST endpoint
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
METADATA_KEY = "__jararaca_expose_type__"
|
|
95
|
+
_exposed_types: set[type] = set()
|
|
96
|
+
|
|
97
|
+
def __init__(self) -> None:
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
def __call__(self, cls: type[BASEMODEL_T]) -> type[BASEMODEL_T]:
|
|
101
|
+
"""
|
|
102
|
+
Decorate the type to mark it for explicit TypeScript generation.
|
|
103
|
+
"""
|
|
104
|
+
setattr(cls, self.METADATA_KEY, True)
|
|
105
|
+
ExposeType._exposed_types.add(cls)
|
|
106
|
+
return cls
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def is_exposed_type(cls: type) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Check if the type is marked for explicit exposure.
|
|
112
|
+
"""
|
|
113
|
+
return getattr(cls, ExposeType.METADATA_KEY, False)
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def get_all_exposed_types() -> set[type]:
|
|
117
|
+
"""
|
|
118
|
+
Get all types that have been marked for explicit exposure.
|
|
119
|
+
"""
|
|
120
|
+
return ExposeType._exposed_types.copy()
|