jararaca 0.2.37a10__py3-none-any.whl → 0.2.37a12__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.
@@ -1,278 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: jararaca
3
- Version: 0.2.37a10
4
- Summary: A simple and fast API framework for Python
5
- Home-page: https://github.com/LuscasLeo/jararaca
6
- Author: Lucas S
7
- Author-email: me@luscasleo.dev
8
- Requires-Python: >=3.11,<4.0
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.11
11
- Classifier: Programming Language :: Python :: 3.12
12
- Classifier: Programming Language :: Python :: 3.13
13
- Provides-Extra: docs
14
- Provides-Extra: http
15
- Provides-Extra: opentelemetry
16
- Requires-Dist: aio-pika (>=9.4.3,<10.0.0)
17
- Requires-Dist: croniter (>=3.0.3,<4.0.0)
18
- Requires-Dist: fastapi (>=0.113.0,<0.114.0)
19
- Requires-Dist: mako (>=1.3.5,<2.0.0)
20
- Requires-Dist: opentelemetry-api (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
21
- Requires-Dist: opentelemetry-distro (>=0.49b2,<0.50) ; extra == "opentelemetry"
22
- Requires-Dist: opentelemetry-exporter-otlp (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
23
- Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
24
- Requires-Dist: opentelemetry-sdk (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
25
- Requires-Dist: redis (>=5.0.8,<6.0.0)
26
- Requires-Dist: sqlalchemy (>=2.0.34,<3.0.0)
27
- Requires-Dist: types-croniter (>=3.0.3.20240731,<4.0.0.0)
28
- Requires-Dist: types-redis (>=4.6.0.20240903,<5.0.0.0)
29
- Requires-Dist: uvicorn (>=0.30.6,<0.31.0)
30
- Requires-Dist: uvloop (>=0.20.0,<0.21.0)
31
- Requires-Dist: websockets (>=13.0.1,<14.0.0)
32
- Project-URL: Repository, https://github.com/LuscasLeo/jararaca
33
- Description-Content-Type: text/markdown
34
-
35
- <img src="https://raw.githubusercontent.com/LuscasLeo/jararaca/main/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg" alt="README.md" width="250" float="right">
36
-
37
- # Jararaca Microservice Framework
38
-
39
- ## Overview
40
-
41
- Jararaca is a aio-first microservice framework that provides a set of tools to build and deploy microservices in a simple and clear way.
42
-
43
- ## Features
44
-
45
- ### Hexagonal Architecture
46
-
47
- The framework is based on the hexagonal architecture, which allows you to separate the business logic from the infrastructure, making the code more testable and maintainable.
48
-
49
- ### Dependency Injection
50
-
51
- The framework uses the dependency injection pattern to manage the dependencies between the components of the application.
52
-
53
- ```py
54
- app = Microservice(
55
- providers=[
56
- ProviderSpec(
57
- provide=Token(AuthConfig, "AUTH_CONFIG"),
58
- use_value=AuthConfig(
59
- secret="secret",
60
- identity_refresh_token_expires_delta_seconds=60 * 60 * 24 * 30,
61
- identity_token_expires_delta_seconds=60 * 60,
62
- ),
63
- ),
64
- ProviderSpec(
65
- provide=Token(AppConfig, "APP_CONFIG"),
66
- use_factory=AppConfig.provider,
67
- ),
68
- ProviderSpec(
69
- provide=TokenBlackListService,
70
- use_value=InMemoryTokenBlackListService(),
71
- ),
72
- ],
73
- )
74
- ```
75
-
76
- ### Web Server Port
77
-
78
- The framework provides a web server that listens on a specific port and routes the requests to the appropriate handler. It uses [FastAPI](https://fastapi.tiangolo.com/) as the web framework.
79
-
80
- ```py
81
- @Delete("/{task_id}")
82
- async def delete_task(self, task_id: TaskId) -> None:
83
- await self.tasks_crud.delete_by_id(task_id)
84
-
85
- await use_ws_manager().broadcast(("Task %s deleted" % task_id).encode())
86
- ```
87
-
88
- ### Message Bus
89
-
90
- The framework provides a topic-based message bus that allows you to send messages between the components of the application. It uses [AIO Pika](https://aio-pika.readthedocs.io/) as the message broker worker and publisher.
91
-
92
- ```py
93
- @IncomingHandler("task")
94
- async def process_task(self, message: Message[Identifiable[TaskSchema]]) -> None:
95
- name = generate_random_name()
96
- now = asyncio.get_event_loop().time()
97
- print("Processing task: ", name)
98
-
99
- task = message.payload()
100
-
101
- print("Received task: ", task)
102
- await asyncio.sleep(random.randint(1, 5))
103
-
104
- await use_publisher().publish(task, topic="task")
105
-
106
- then = asyncio.get_event_loop().time()
107
- print("Task Finished: ", name, " Time: ", then - now)
108
- ```
109
-
110
- ### Distributed Websocket
111
-
112
- You can setup a room-based websocket server that allows you to send messages to a specific room or broadcast messages to all connected clients. All backend instances communicates with each other using a pub/sub mechanism (such as Redis).
113
-
114
- ```py
115
- @WebSocketEndpoint("/ws")
116
- async def ws_endpoint(self, websocket: WebSocket) -> None:
117
- await websocket.accept()
118
- counter.increment()
119
- await use_ws_manager().add_websocket(websocket)
120
- await use_ws_manager().join(["tasks"], websocket)
121
- await use_ws_manager().broadcast(
122
- ("New Connection (%d) from %s" % (counter.count, self.hostname)).encode()
123
- )
124
-
125
- print("New Connection (%d)" % counter.count)
126
-
127
- while True:
128
- try:
129
- await websocket.receive_text()
130
- except WebSocketDisconnect:
131
- counter.decrement()
132
- await use_ws_manager().remove_websocket(websocket)
133
-
134
- await use_ws_manager().broadcast(
135
- (
136
- "Connection Closed (%d) from %s"
137
- % (counter.count, self.hostname)
138
- ).encode()
139
- )
140
- print("Connection Closed (%d)" % counter.count)
141
- break
142
- ```
143
-
144
- ### Scheduled Routine
145
-
146
- You can setup a scheduled routine that runs a specific task at a specific time or interval.
147
-
148
- ```py
149
- ...
150
- @ScheduledAction("* * * * * */3", allow_overlap=False)
151
- async def scheduled_task(self) -> None:
152
- print("Scheduled Task at ", asyncio.get_event_loop().time())
153
-
154
- print("sleeping")
155
- await asyncio.sleep(5)
156
-
157
- await use_publisher().publish(
158
- message=Identifiable(
159
- id=uuid4(),
160
- data=TaskSchema(name=generate_random_name()),
161
- ),
162
- topic="task",
163
- )
164
- ```
165
-
166
- ### Observability
167
-
168
- You can setup Observability Interceptors for logs, traces and metric collection with [OpenTelemetry](https://opentelemetry.io/docs)-based Protocols
169
-
170
- ```python
171
- class HelloService:
172
- def __init__(
173
- self,
174
- hello_rpc: Annotated[HelloRPC, Token(HelloRPC, "HELLO_RPC")],
175
- ):
176
- self.hello_rpc = hello_rpc
177
-
178
- @TracedFunc("ping") # Decorator for tracing
179
- async def ping(self) -> HelloResponse:
180
- return await self.hello_rpc.ping()
181
-
182
- @TracedFunc("hello-service")
183
- async def hello(
184
- self,
185
- gather: bool,
186
- ) -> HelloResponse:
187
- now = asyncio.get_event_loop().time()
188
- if gather:
189
- await asyncio.gather(*[self.random_await(a) for a in range(10)])
190
- else:
191
- for a in range(10):
192
- await self.random_await(a)
193
- return HelloResponse(
194
- message="Elapsed time: {}".format(asyncio.get_event_loop().time() - now)
195
- )
196
-
197
- @TracedFunc("random-await")
198
- async def random_await(self, index: int) -> None:
199
- logger.info("Random await %s", index, extra={"index": index})
200
- await asyncio.sleep(random.randint(1, 3))
201
- logger.info("Random await %s done", index, extra={"index": index})
202
- ```
203
-
204
- ## Installation
205
-
206
- ```bash
207
- pip install jararaca
208
- ```
209
-
210
- ## Usage
211
-
212
- ### Create a Microservice
213
-
214
- ```python
215
- # app.py
216
-
217
- from jararaca import Microservice, create_http_server, create_messagebus_worker
218
- from jararaca.presentation.http_microservice import HttpMicroservice
219
-
220
- app = Microservice(
221
- providers=[
222
- ProviderSpec(
223
- provide=Token[AppConfig],
224
- use_factory=AppConfig.provider,
225
- )
226
- ],
227
- controllers=[TasksController],
228
- interceptors=[
229
- AIOSqlAlchemySessionInterceptor(
230
- AIOSQAConfig(
231
- connection_name="default",
232
- url="sqlite+aiosqlite:///db.sqlite3",
233
- )
234
- ),
235
- ],
236
- )
237
-
238
-
239
- # App for specific Http Configuration Context
240
- http_app = HttpMicroservice(app)
241
-
242
- web_app = create_http_server(app)
243
-
244
- ```
245
-
246
- ### Run as a Web Server
247
-
248
- ```bash
249
- uvicorn app:web_app --reload
250
- # or
251
- jararaca server app:app
252
- # or
253
- jararaca server app:http_app
254
-
255
- ```
256
-
257
- ### Run as a Message Bus Worker
258
-
259
- ```bash
260
- jararaca worker app:app
261
- ```
262
-
263
- ### Run as a scheduled routine
264
-
265
- ```bash
266
- jararaca scheduler app:app
267
- ```
268
-
269
- ### Generate Typescript intefaces from microservice app controllers
270
-
271
- ```bash
272
- jararaca gen-tsi app.main:app app.ts
273
- ```
274
-
275
- ### Documentation
276
-
277
- Documentation is under construction [here](https://luscasleo.github.io/jararaca/).
278
-
pyproject.toml DELETED
@@ -1,77 +0,0 @@
1
- [tool.poetry]
2
- name = "jararaca"
3
- version = "0.2.37a10"
4
- description = "A simple and fast API framework for Python"
5
- authors = ["Lucas S <me@luscasleo.dev>"]
6
- readme = "README.md"
7
- packages = [{ include = "jararaca", from = "src" }]
8
- include = ["pyproject.toml", "README.md", "LICENSE", "docs"]
9
- repository = "https://github.com/LuscasLeo/jararaca"
10
-
11
-
12
- [tool.poetry.dependencies]
13
- python = "^3.11"
14
- uvicorn = "^0.30.6"
15
- uvloop = "^0.20.0"
16
- fastapi = "^0.113.0"
17
- aio-pika = "^9.4.3"
18
- sqlalchemy = "^2.0.34"
19
- croniter = "^3.0.3"
20
- redis = "^5.0.8"
21
- websockets = "^13.0.1"
22
- opentelemetry-exporter-otlp-proto-http = { version = "^1.27.0", optional = true }
23
- opentelemetry-api = { version = "^1.27.0", optional = true }
24
- opentelemetry-sdk = { version = "^1.27.0", optional = true }
25
- opentelemetry-distro = { version = "^0.49b2", optional = true }
26
- opentelemetry-exporter-otlp = { version = "^1.27.0", optional = true }
27
- types-croniter = "^3.0.3.20240731"
28
- types-redis = "^4.6.0.20240903"
29
- mako = "^1.3.5"
30
-
31
-
32
- [tool.poetry.extras]
33
- opentelemetry = [
34
- "opentelemetry-exporter-otlp-proto-http",
35
- "opentelemetry-api",
36
- "opentelemetry-sdk",
37
- "opentelemetry-distro",
38
- "opentelemetry-exporter-otlp",
39
- ]
40
- http = ["httptools", "httpx"]
41
- docs = ["mkdocs-material"]
42
-
43
- [tool.poetry.group.lint.dependencies]
44
- mypy = "^1.11.2"
45
- black = "^24.8.0"
46
- isort = "^5.13.2"
47
- pre-commit = "^3.8.0"
48
- autoflake = "^2.3.1"
49
- types-croniter = "^3.0.3.20240731"
50
- types-redis = "^4.6.0.20240903"
51
-
52
-
53
- [tool.poetry.group.docs.dependencies]
54
- mkdocs-material = "^9.5.34"
55
-
56
-
57
- [tool.poetry.group.dev.dependencies]
58
- httptools = "^0.6.1"
59
- httpx = "^0.27.2"
60
-
61
- [build-system]
62
- requires = ["poetry-core"]
63
- build-backend = "poetry.core.masonry.api"
64
-
65
-
66
- [tool.isort]
67
- profile = "black"
68
-
69
- [tool.mypy]
70
- python_version = "3.11"
71
- strict = true
72
- # mypy_path = "src"
73
-
74
-
75
- # JARARACA CONFIG
76
- [tool.poetry.scripts]
77
- jararaca = "jararaca.cli:cli"
File without changes