44
55from celery import Task # type: ignore
66from vintasend .services .dataclasses import (
7+ AttachmentFile ,
78 Notification ,
89 NotificationContextDict ,
910 OneOffNotification ,
2223T = TypeVar ("T" , bound = BaseNotificationTemplateRenderer )
2324
2425
26+ class PlaceholderAttachmentFile (AttachmentFile ):
27+ """
28+ Placeholder for AttachmentFile.
29+ All file operations raise NotImplementedError and must be handled by the caller.
30+ Use this class only when the actual file is expected to be retrieved by the backend.
31+ """
32+ def __init__ (self , attachment_id ):
33+ self .attachment_id = attachment_id
34+
35+ def read (self ) -> bytes :
36+ """
37+ Attempting to read will raise NotImplementedError.
38+ Caller must handle this exception and retrieve the file from the backend.
39+ """
40+ raise NotImplementedError ("File must be retrieved from backend" )
41+
42+ def stream (self ):
43+ """
44+ Attempting to stream will raise NotImplementedError.
45+ Caller must handle this exception and retrieve the file from the backend.
46+ """
47+ raise NotImplementedError ("File must be retrieved from backend" )
48+
49+ def url (self , expires_in : int = 3600 ) -> str :
50+ """
51+ Attempting to get a URL will raise NotImplementedError.
52+ Caller must handle this exception and retrieve the file from the backend.
53+ """
54+ raise NotImplementedError ("File must be retrieved from backend" )
55+
56+ def delete (self ) -> None :
57+ """
58+ Attempting to delete will raise NotImplementedError.
59+ Caller must handle this exception and perform deletion via the backend.
60+ """
61+ raise NotImplementedError ("File must be retrieved from backend" )
62+
63+
2564class CeleryNotificationAdapter (Generic [B , T ], AsyncBaseNotificationAdapter [B , T ]):
2665 send_notification_task : Task
2766
@@ -61,15 +100,10 @@ def notification_to_dict(self, notification: "Notification | OneOffNotification"
61100 "one_off" if isinstance (notification , OneOffNotification ) else "regular"
62101 )
63102
64- # Add specific fields based on notification type
65- if isinstance (notification , OneOffNotification ):
66- # Set adapter_extra_parameters if missing
67- if "adapter_extra_parameters" not in serialized_notification :
68- serialized_notification ["adapter_extra_parameters" ] = getattr (notification , 'adapter_extra_parameters' , {})
69- else :
70- # For regular notifications, ensure adapter_extra_parameters exists
71- if "adapter_extra_parameters" not in serialized_notification :
72- serialized_notification ["adapter_extra_parameters" ] = getattr (notification , 'adapter_extra_parameters' , None )
103+ # Ensure adapter_extra_parameters exists for all notification types
104+ if "adapter_extra_parameters" not in serialized_notification :
105+ default_value : dict [str , Any ] | None = {} if isinstance (notification , OneOffNotification ) else None
106+ serialized_notification ["adapter_extra_parameters" ] = getattr (notification , 'adapter_extra_parameters' , default_value )
73107
74108 # Ensure context_used exists
75109 if "context_used" not in serialized_notification :
@@ -123,11 +157,11 @@ def _serialize_attachment(self, attachment) -> dict:
123157 size = 0
124158
125159 return {
126- "id" : f"temp_{ hash ( attachment . filename )} " , # Temporary ID
160+ "id" : f"temp_{ uuid . uuid4 ( )} " , # Temporary ID, guaranteed unique
127161 "filename" : attachment .filename ,
128162 "content_type" : attachment .content_type ,
129163 "size" : size ,
130- "checksum" : "placeholder" , # Will be calculated by backend
164+ "checksum" : None , # Will be calculated by backend
131165 "created_at" : datetime .datetime .now ().isoformat (),
132166 "description" : attachment .description ,
133167 "is_inline" : attachment .is_inline ,
@@ -139,26 +173,7 @@ def _serialize_attachment(self, attachment) -> dict:
139173
140174 def _deserialize_attachment (self , attachment_dict : dict ) -> StoredAttachment :
141175 """Deserialize an attachment dictionary back to StoredAttachment."""
142- # We need to create a placeholder AttachmentFile that can be resolved by the backend
143- from vintasend .services .dataclasses import AttachmentFile
144-
145- # Create a dummy AttachmentFile - the actual file will be retrieved by the backend
146- class PlaceholderAttachmentFile (AttachmentFile ):
147- def __init__ (self , attachment_id ):
148- self .attachment_id = attachment_id
149-
150- def read (self ) -> bytes :
151- raise NotImplementedError ("File must be retrieved from backend" )
152-
153- def stream (self ):
154- raise NotImplementedError ("File must be retrieved from backend" )
155-
156- def url (self , expires_in : int = 3600 ) -> str :
157- raise NotImplementedError ("File must be retrieved from backend" )
158-
159- def delete (self ) -> None :
160- raise NotImplementedError ("File must be retrieved from backend" )
161-
176+ # WARNING: PlaceholderAttachmentFile methods raise NotImplementedError. Handle accordingly.
162177 return StoredAttachment (
163178 id = attachment_dict ["id" ],
164179 filename = attachment_dict ["filename" ],
0 commit comments