jararaca 0.3.0__tar.gz → 0.3.1__tar.gz

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 jararaca might be problematic. Click here for more details.

Files changed (82) hide show
  1. {jararaca-0.3.0 → jararaca-0.3.1}/PKG-INFO +1 -1
  2. {jararaca-0.3.0 → jararaca-0.3.1}/docs/scheduler.md +10 -7
  3. {jararaca-0.3.0 → jararaca-0.3.1}/pyproject.toml +1 -1
  4. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/cli.py +56 -25
  5. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +5 -4
  6. {jararaca-0.3.0 → jararaca-0.3.1}/LICENSE +0 -0
  7. {jararaca-0.3.0 → jararaca-0.3.1}/README.md +0 -0
  8. {jararaca-0.3.0 → jararaca-0.3.1}/docs/CNAME +0 -0
  9. {jararaca-0.3.0 → jararaca-0.3.1}/docs/architecture.md +0 -0
  10. {jararaca-0.3.0 → jararaca-0.3.1}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
  11. {jararaca-0.3.0 → jararaca-0.3.1}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
  12. {jararaca-0.3.0 → jararaca-0.3.1}/docs/assets/tracing_example.png +0 -0
  13. {jararaca-0.3.0 → jararaca-0.3.1}/docs/index.md +0 -0
  14. {jararaca-0.3.0 → jararaca-0.3.1}/docs/messagebus.md +0 -0
  15. {jararaca-0.3.0 → jararaca-0.3.1}/docs/stylesheets/custom.css +0 -0
  16. {jararaca-0.3.0 → jararaca-0.3.1}/docs/websocket.md +0 -0
  17. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/__init__.py +0 -0
  18. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/__main__.py +0 -0
  19. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/broker_backend/__init__.py +0 -0
  20. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/broker_backend/mapper.py +0 -0
  21. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/broker_backend/redis_broker_backend.py +0 -0
  22. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/common/__init__.py +0 -0
  23. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/core/__init__.py +0 -0
  24. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/core/providers.py +0 -0
  25. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/core/uow.py +0 -0
  26. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/di.py +0 -0
  27. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/files/entity.py.mako +0 -0
  28. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/lifecycle.py +0 -0
  29. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/__init__.py +0 -0
  30. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/bus_message_controller.py +0 -0
  31. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/consumers/__init__.py +0 -0
  32. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/decorators.py +0 -0
  33. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
  34. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/interceptors/publisher_interceptor.py +0 -0
  35. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/message.py +0 -0
  36. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/publisher.py +0 -0
  37. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/worker.py +0 -0
  38. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/messagebus/worker_v2.py +0 -0
  39. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/microservice.py +0 -0
  40. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/observability/decorators.py +0 -0
  41. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/observability/interceptor.py +0 -0
  42. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/observability/providers/__init__.py +0 -0
  43. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/observability/providers/otel.py +0 -0
  44. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/persistence/base.py +0 -0
  45. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/persistence/exports.py +0 -0
  46. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/persistence/interceptors/__init__.py +0 -0
  47. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -0
  48. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/persistence/session.py +0 -0
  49. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/persistence/sort_filter.py +0 -0
  50. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/persistence/utilities.py +0 -0
  51. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/__init__.py +0 -0
  52. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/decorators.py +0 -0
  53. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/hooks.py +0 -0
  54. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/http_microservice.py +0 -0
  55. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/server.py +0 -0
  56. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/websocket/__init__.py +0 -0
  57. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/websocket/base_types.py +0 -0
  58. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/websocket/context.py +0 -0
  59. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/websocket/decorators.py +0 -0
  60. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/websocket/redis.py +0 -0
  61. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/websocket/types.py +0 -0
  62. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
  63. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/py.typed +0 -0
  64. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/rpc/__init__.py +0 -0
  65. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/rpc/http/__init__.py +0 -0
  66. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/rpc/http/backends/__init__.py +0 -0
  67. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/rpc/http/backends/httpx.py +0 -0
  68. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/rpc/http/backends/otel.py +0 -0
  69. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/rpc/http/decorators.py +0 -0
  70. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/rpc/http/httpx.py +0 -0
  71. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/scheduler/__init__.py +0 -0
  72. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/scheduler/decorators.py +0 -0
  73. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/scheduler/scheduler.py +0 -0
  74. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/scheduler/scheduler_v2.py +0 -0
  75. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/scheduler/types.py +0 -0
  76. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/tools/app_config/__init__.py +0 -0
  77. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/tools/app_config/decorators.py +0 -0
  78. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/tools/app_config/interceptor.py +0 -0
  79. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/tools/metadata.py +0 -0
  80. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/tools/typescript/interface_parser.py +0 -0
  81. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/utils/__init__.py +0 -0
  82. {jararaca-0.3.0 → jararaca-0.3.1}/src/jararaca/utils/rabbitmq_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: jararaca
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: A simple and fast API framework for Python
5
5
  Author: Lucas S
6
6
  Author-email: me@luscasleo.dev
@@ -21,7 +21,7 @@ graph TD
21
21
  A[Microservice] --> B[Scheduler System]
22
22
  B --> C[Basic Scheduler]
23
23
  B --> D[Enhanced Scheduler V2]
24
-
24
+
25
25
  C --> E[Local Task Execution]
26
26
  D --> F[Message Broker]
27
27
  F --> G[Workers]
@@ -39,12 +39,13 @@ You can define scheduled tasks using the `@ScheduledAction` decorator:
39
39
  ```python
40
40
  from jararaca import ScheduledAction
41
41
 
42
+
42
43
  class TasksController:
43
44
  @ScheduledAction("*/5 * * * *") # Run every 5 minutes
44
45
  async def scheduled_task(self):
45
46
  # Your task implementation
46
47
  print("This runs every 5 minutes")
47
-
48
+
48
49
  @ScheduledAction("0 */2 * * *", allow_overlap=False, timeout=60)
49
50
  async def heavy_task(self):
50
51
  # A heavier task that shouldn't overlap
@@ -85,6 +86,7 @@ app = Microservice(
85
86
 
86
87
  # Run the scheduler
87
88
  from jararaca.scheduler.scheduler import Scheduler
89
+
88
90
  scheduler = Scheduler(app, interval=1)
89
91
  scheduler.run()
90
92
  ```
@@ -128,7 +130,7 @@ sequenceDiagram
128
130
  participant B as Message Broker
129
131
  participant R as Redis Backend
130
132
  participant W as Worker
131
-
133
+
132
134
  S->>R: Check last execution time
133
135
  R-->>S: Return last execution time
134
136
  S->>S: Determine if task should run
@@ -148,19 +150,20 @@ The V2 scheduler also supports delayed messages:
148
150
  from jararaca import use_publisher
149
151
  from jararaca.scheduler.types import DelayedMessageData
150
152
 
153
+
151
154
  # Schedule a message to be published at a future time
152
155
  async def schedule_reminder():
153
156
  message = ReminderMessage(
154
157
  user_id="123",
155
158
  message="Don't forget your appointment!"
156
159
  )
157
-
160
+
158
161
  # Current time + 1 hour in seconds
159
162
  dispatch_time = int(time.time()) + 3600
160
-
163
+
161
164
  # Get publisher
162
165
  publisher = use_publisher()
163
-
166
+
164
167
  # Schedule delayed message
165
168
  await publisher.publish_delayed(
166
169
  message,
@@ -213,4 +216,4 @@ jararaca scheduler_v2 APP_PATH [OPTIONS]
213
216
 
214
217
  ## Conclusion
215
218
 
216
- The Jararaca scheduler system provides a powerful, flexible way to implement periodic tasks in your applications. With two implementations to choose from, you can select the one that best fits your application's requirements, from simple local scheduling to complex distributed task execution.
219
+ The Jararaca scheduler system provides a powerful, flexible way to implement periodic tasks in your applications. With two implementations to choose from, you can select the one that best fits your application's requirements, from simple local scheduling to complex distributed task execution.
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.3.0"
3
+ version = "0.3.1"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"
@@ -1,9 +1,11 @@
1
1
  import importlib
2
2
  import importlib.resources
3
+ import multiprocessing
3
4
  import os
4
5
  import sys
5
6
  import time
6
7
  from codecs import StreamWriter
8
+ from pathlib import Path
7
9
  from typing import Any
8
10
  from urllib.parse import urlparse, urlunsplit
9
11
 
@@ -265,6 +267,30 @@ def scheduler_v2(
265
267
  scheduler.run()
266
268
 
267
269
 
270
+ def generate_interfaces(app_path: str, file_path: str) -> None:
271
+ try:
272
+ app = find_microservice_by_module_path(app_path)
273
+ content = write_microservice_to_typescript_interface(app)
274
+
275
+ with open(file_path, "w", encoding="utf-8") as file:
276
+ # Save current position
277
+ file.tell()
278
+
279
+ # Reset file to beginning
280
+ file.seek(0)
281
+ file.truncate()
282
+
283
+ # Write new content
284
+ file.write(content)
285
+ file.flush()
286
+
287
+ print(
288
+ f"Generated TypeScript interfaces at {time.strftime('%H:%M:%S')} at {str(Path(file_path).absolute())}"
289
+ )
290
+ except Exception as e:
291
+ print(f"Error generating TypeScript interfaces: {e}", file=sys.stderr)
292
+
293
+
268
294
  @cli.command()
269
295
  @click.argument(
270
296
  "app_path",
@@ -272,7 +298,7 @@ def scheduler_v2(
272
298
  )
273
299
  @click.argument(
274
300
  "file_path",
275
- type=click.File("w"),
301
+ type=click.Path(file_okay=True, dir_okay=False),
276
302
  )
277
303
  @click.option(
278
304
  "--watch",
@@ -283,32 +309,11 @@ def scheduler_v2(
283
309
  type=click.Path(exists=True, file_okay=False, dir_okay=True),
284
310
  default="src",
285
311
  )
286
- def gen_tsi(app_path: str, file_path: StreamWriter, watch: bool, src_dir: str) -> None:
312
+ def gen_tsi(app_path: str, file_path: str, watch: bool, src_dir: str) -> None:
287
313
  """Generate TypeScript interfaces from a Python microservice."""
288
314
 
289
- # Generate typescript interfaces
290
- def generate_interfaces() -> None:
291
- try:
292
- app = find_microservice_by_module_path(app_path)
293
- content = write_microservice_to_typescript_interface(app)
294
-
295
- # Save current position
296
- file_path.tell()
297
-
298
- # Reset file to beginning
299
- file_path.seek(0)
300
- file_path.truncate()
301
-
302
- # Write new content
303
- file_path.write(content)
304
- file_path.flush()
305
-
306
- print(f"Generated TypeScript interfaces at {time.strftime('%H:%M:%S')}")
307
- except Exception as e:
308
- print(f"Error generating TypeScript interfaces: {e}", file=sys.stderr)
309
-
310
315
  # Initial generation
311
- generate_interfaces()
316
+ generate_interfaces(app_path, file_path)
312
317
 
313
318
  # If watch mode is not enabled, exit
314
319
  if not watch:
@@ -334,7 +339,33 @@ def gen_tsi(app_path: str, file_path: StreamWriter, watch: bool, src_dir: str) -
334
339
  )
335
340
  if not event.is_directory and src_path.endswith(".py"):
336
341
  print(f"File changed: {src_path}")
337
- generate_interfaces()
342
+ # Create a completely detached process to ensure classes are reloaded
343
+ process = multiprocessing.get_context("spawn").Process(
344
+ target=generate_interfaces,
345
+ args=(app_path, file_path),
346
+ daemon=False, # Non-daemon to ensure it completes
347
+ )
348
+ process.start()
349
+ # Don't join to keep it detached from main process
350
+
351
+ def _run_generator_in_separate_process(
352
+ self, app_path: str, file_path: str
353
+ ) -> None:
354
+ # Using Python executable to start a completely new process
355
+ # This ensures all modules are freshly imported
356
+ generate_interfaces(app_path, file_path)
357
+ # cmd = [
358
+ # sys.executable,
359
+ # "-c",
360
+ # (
361
+ # f"import sys; sys.path.extend({sys.path}); "
362
+ # f"from jararaca.cli import generate_interfaces; "
363
+ # f"generate_interfaces('{app_path}', '{file_path}')"
364
+ # ),
365
+ # ]
366
+ # import subprocess
367
+
368
+ # subprocess.run(cmd, check=False)
338
369
 
339
370
  # Set up observer
340
371
  observer = Observer()
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  from contextlib import asynccontextmanager
2
3
  from datetime import datetime, timedelta
3
4
  from datetime import tzinfo as _TzInfo
@@ -29,10 +30,10 @@ class AIOPikaMessagePublisher(MessagePublisher):
29
30
  self.message_broker_backend = message_broker_backend
30
31
 
31
32
  async def publish(self, message: IMessage, topic: str) -> None:
32
- exchange = await self.channel.declare_exchange(
33
- self.exchange_name,
34
- type=aio_pika.ExchangeType.TOPIC,
35
- )
33
+ exchange = await self.channel.get_exchange(self.exchange_name, ensure=False)
34
+ if not exchange:
35
+ logging.warning(f"Exchange {self.exchange_name} not found")
36
+ return
36
37
  routing_key = f"{topic}."
37
38
  await exchange.publish(
38
39
  aio_pika.Message(body=message.model_dump_json().encode()),
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes