Skip to content

Commit

Permalink
Fixes celery setup and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hugobessa committed Dec 11, 2024
1 parent 03ed843 commit b8ef3a9
Show file tree
Hide file tree
Showing 7 changed files with 395 additions and 151 deletions.
67 changes: 67 additions & 0 deletions example_app/celery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from datetime import datetime
from decimal import Decimal

import pytest
from celery import Celery # type: ignore
from vintasend.services.notification_adapters.stubs.fake_adapter import (
FakeEmailAdapter,
)
from vintasend.services.notification_backends.stubs.fake_backend import (
Config,
FakeFileBackend,
FakeFileBackendWithNonSerializableKWArgs,
)
from vintasend.services.notification_template_renderers.stubs.fake_templated_email_renderer import (
FakeTemplateRenderer,
)
from vintasend.tasks.background_tasks import send_notification

from vintasend_celery.services.notification_adapters.celery_adapter_factory import (
CeleryNotificationAdapter,
)


celery_app = Celery(
"tasks", broker="memory://localhost/", backend="cache+memory://", task_always_eager=True
)


@celery_app.task
def send_notification_task(*args, **kwargs):
send_notification(*args, **kwargs)


class AsyncCeleryFakeEmailAdapter(
CeleryNotificationAdapter[FakeFileBackend, FakeTemplateRenderer],
FakeEmailAdapter[FakeFileBackend, FakeTemplateRenderer],
):
send_notification_task = send_notification_task


class AsyncCeleryFakeEmailAdapterWithBackendWithNonSerializableKWArgs(
CeleryNotificationAdapter[FakeFileBackendWithNonSerializableKWArgs, FakeTemplateRenderer],
FakeEmailAdapter[FakeFileBackendWithNonSerializableKWArgs, FakeTemplateRenderer],
):
send_notification_task = send_notification_task
config: Config

def serialize_config(self) -> dict[str, str]:
return {
"config_a": str(self.config.config_a),
"config_b": self.config.config_b.isoformat(),
}

@staticmethod
def restore_config(config: dict[str, str]) -> Config:
return Config(
config_a=Decimal(config["config_a"]),
config_b=datetime.fromisoformat(config["config_b"]),
)


@pytest.fixture(scope="session")
def celery_includes():
return [
"proj.tests.tasks",
"proj.tests.celery_signal_handlers",
]
164 changes: 162 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pytest = "^8.3.3"
pytest-xdist = {version = "^3.6.1", extras=["psutil"]}
coveralls = "^4.0.1"
pytest-cov = "^6.0.0"
pytest-celery = "^1.1.3"

[build-system]
requires = ["poetry-core"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import datetime
from typing import cast, Generic, TypeVar

from celery import Celery # type: ignore
import uuid
from typing import Generic, TypeVar, cast

from celery import Task # type: ignore
from vintasend.services.dataclasses import Notification, NotificationContextDict
from vintasend.services.notification_adapters.async_base import AsyncBaseNotificationAdapter, NotificationDict
from vintasend.services.notification_adapters.async_base import (
AsyncBaseNotificationAdapter,
NotificationDict,
)
from vintasend.services.notification_backends.base import BaseNotificationBackend
from vintasend.services.notification_template_renderers.base import BaseNotificationTemplateRenderer
from vintasend_celery.tasks.background_tasks import send_notification_task_factory


B = TypeVar("B", bound=BaseNotificationBackend)
T = TypeVar("T", bound=BaseNotificationTemplateRenderer)

class CeleryNotificationAdapter(Generic[B, T], AsyncBaseNotificationAdapter[B, T]):
celery_app: Celery
send_notification_task: Task

def delayed_send(self, notification_dict: dict, context_dict: dict) -> None:
def delayed_send(self, notification_dict: NotificationDict, context_dict: dict) -> None:
print("ENTROU AQUI!!!!!!!!!!!!!!!")
notification = self.notification_from_dict(notification_dict)
context = NotificationContextDict(**context_dict)
super().send(notification, context) # type: ignore
Expand All @@ -34,18 +37,47 @@ def notification_to_dict(self, notification: "Notification") -> NotificationDict
)

return cast(NotificationDict, serialized_notification)

def _convert_to_uuid(self, value: str) -> uuid.UUID | str:
try:
return uuid.UUID(value)
except ValueError:
return value

def notification_from_dict(self, notification_dict: dict) -> "Notification":
notification_dict["send_after"] = (
def notification_from_dict(self, notification_dict: NotificationDict) -> "Notification":
send_after = (
datetime.datetime.fromisoformat(notification_dict["send_after"])
if notification_dict["send_after"]
else None
)
return Notification(**notification_dict)
return Notification(
id=(
self._convert_to_uuid(notification_dict["id"])
if isinstance(notification_dict["id"], str)
else notification_dict["id"]
),
user_id=(
self._convert_to_uuid(notification_dict["user_id"])
if isinstance(notification_dict["user_id"], str)
else notification_dict["user_id"]
),
context_kwargs={
key: self._convert_to_uuid(value) if isinstance(value, str) else value
for key, value in notification_dict["context_kwargs"].items()
},
notification_type=notification_dict["notification_type"],
title=notification_dict["title"],
body_template=notification_dict["body_template"],
context_name=notification_dict["context_name"],
subject_template=notification_dict["subject_template"],
preheader_template=notification_dict["preheader_template"],
status=notification_dict["status"],
context_used=notification_dict["context_used"],
send_after=send_after,
)

def send(self, notification: "Notification", context: "NotificationContextDict") -> None:
send_notification_task = send_notification_task_factory(self.celery_app)
send_notification_task.delay(
self.send_notification_task.delay(
notification=self.notification_to_dict(notification),
context=context,
backend=self.backend.backend_import_str,
Expand Down
1 change: 0 additions & 1 deletion vintasend_celery/tasks/background_tasks.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import logging

from celery import Celery # type: ignore

from vintasend.tasks.background_tasks import send_notification


Expand Down
1 change: 0 additions & 1 deletion vintasend_celery/tasks/periodic_tasks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from celery import Celery # type: ignore

from vintasend.tasks.periodic_tasks import periodic_send_pending_notifications


Expand Down
Loading

0 comments on commit b8ef3a9

Please sign in to comment.