celery-fastapi 0.1.1__tar.gz → 0.1.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: celery-fastapi
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: Automatic REST API generation for Celery tasks with FastAPI
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -72,6 +72,30 @@ app = typer.Typer(
72
72
  console = Console()
73
73
 
74
74
 
75
+ def _create_app_from_env() -> Any:
76
+ """
77
+ Factory function to create FastAPI app from environment variables.
78
+
79
+ This is used when running with multiple workers or reload enabled,
80
+ as uvicorn requires an import string in these cases.
81
+ """
82
+ from celery_fastapi.app import create_app
83
+
84
+ celery_app = os.environ.get("CELERY_FASTAPI_CELERY_APP")
85
+ prefix = os.environ.get("CELERY_FASTAPI_PREFIX", "")
86
+ root_path = os.environ.get("CELERY_FASTAPI_ROOT_PATH", "")
87
+
88
+ if not celery_app:
89
+ raise ValueError("CELERY_FASTAPI_CELERY_APP environment variable not set")
90
+
91
+ return create_app(
92
+ celery_app,
93
+ title="Celery FastAPI",
94
+ prefix=prefix,
95
+ fastapi_kwargs={"root_path": root_path} if root_path else None,
96
+ )
97
+
98
+
75
99
  def version_callback(value: bool) -> None:
76
100
  """Print version and exit."""
77
101
  if value:
@@ -374,7 +398,19 @@ def serve(
374
398
  console.print("[dim]Press CTRL+C to stop[/]\n")
375
399
 
376
400
  # Run the server
377
- uvicorn.run(fastapi_app, **uvicorn_config)
401
+ # When using workers > 1 or reload, we need to use an import string
402
+ if workers > 1 or reload:
403
+ # Set environment variables for the factory to use
404
+ os.environ["CELERY_FASTAPI_CELERY_APP"] = celery_app
405
+ os.environ["CELERY_FASTAPI_PREFIX"] = prefix
406
+ if root_path:
407
+ os.environ["CELERY_FASTAPI_ROOT_PATH"] = root_path
408
+
409
+ # Use the factory function as an import string
410
+ uvicorn.run("celery_fastapi.cli:_create_app_from_env", **uvicorn_config)
411
+ else:
412
+ # Single worker, can use app instance directly
413
+ uvicorn.run(fastapi_app, **uvicorn_config)
378
414
 
379
415
 
380
416
  @app.command()
@@ -1,8 +1,9 @@
1
1
  """Core functionality for Celery FastAPI."""
2
2
 
3
3
  import inspect
4
+ from collections.abc import Callable
4
5
  from datetime import datetime
5
- from typing import Any, Callable, get_type_hints
6
+ from typing import Any, get_type_hints
6
7
 
7
8
  from celery import Celery
8
9
  from celery.result import AsyncResult
@@ -222,7 +223,7 @@ def _create_task_payload_model(
222
223
  model_name = f"{task_name.replace('.', '_').title().replace('_', '')}Payload"
223
224
 
224
225
  # Create and return the dynamic model
225
- model: type[BaseModel] = create_model(model_name, **field_definitions) # type: ignore[call-overload]
226
+ model: type[BaseModel] = create_model(model_name, **field_definitions)
226
227
  model.__doc__ = f"Payload for {task_name} task. Default queue: {default_queue}"
227
228
 
228
229
  # Set model config for examples
@@ -324,7 +325,7 @@ class CeleryFastAPIBridge:
324
325
 
325
326
  # Store the registered task names from THIS app only
326
327
  self._app_task_names: set[str] = set()
327
- for name in self.celery_app.tasks.keys():
328
+ for name in self.celery_app.tasks:
328
329
  if self.task_filter(name):
329
330
  self._app_task_names.add(name)
330
331
 
@@ -403,7 +404,9 @@ class CeleryFastAPIBridge:
403
404
  celery_option_names = set(CELERY_OPTIONS_FIELDS.keys())
404
405
  task_kwargs: dict[str, Any] = {}
405
406
 
406
- for field_name in payload.model_fields:
407
+ # Access model_fields from the class, not the instance (Pydantic V2.11+)
408
+ payload_fields = type(payload).model_fields # type: ignore[attr-defined]
409
+ for field_name in payload_fields:
407
410
  if field_name not in celery_option_names:
408
411
  value = getattr(payload, field_name, None)
409
412
  if value is not None:
@@ -751,8 +754,8 @@ class CeleryFastAPIBridge:
751
754
  routes: list[dict[str, str]] = []
752
755
  for route in self.fastapi_app.routes:
753
756
  if hasattr(route, "path") and hasattr(route, "methods"):
754
- path = getattr(route, "path")
755
- methods = getattr(route, "methods")
757
+ path = route.path
758
+ methods = route.methods
756
759
  for method in methods:
757
760
  if method != "HEAD":
758
761
  routes.append({"path": path, "method": method})
@@ -10,7 +10,7 @@ if TYPE_CHECKING:
10
10
 
11
11
  def create_gunicorn_app(
12
12
  app: Any, options: dict[str, Any] | None = None
13
- ) -> "BaseApplication":
13
+ ) -> BaseApplication:
14
14
  """Create a Gunicorn application instance.
15
15
 
16
16
  Args:
@@ -31,7 +31,7 @@ def create_gunicorn_app(
31
31
  "Install with: pip install celery-fastapi[gunicorn]"
32
32
  ) from exc
33
33
 
34
- class _GunicornApp(BaseApplication): # type: ignore[misc]
34
+ class _GunicornApp(BaseApplication):
35
35
  """Internal Gunicorn application wrapper."""
36
36
 
37
37
  def __init__(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "celery-fastapi"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  description = "Automatic REST API generation for Celery tasks with FastAPI"
5
5
  authors = ["ilkerkara <ilkerkara@outlook.com.tr>"]
6
6
  license = "MIT"
File without changes
File without changes