Skip to content
This repository was archived by the owner on Sep 9, 2024. It is now read-only.

Commit 50969a9

Browse files
feat: 100% test coverage
1 parent 31c8b29 commit 50969a9

File tree

6 files changed

+371
-53
lines changed

6 files changed

+371
-53
lines changed

pydantic_sqs/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class MessageNotInQueueError(PydanticSQSError):
1414
pass
1515

1616

17-
class InvaidMessageInQueueError(PydanticSQSError):
17+
class InvalidMessageInQueueError(PydanticSQSError):
1818
pass
1919

2020

pydantic_sqs/model.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Module containing the model classes"""
22
import json
3+
from typing import Any
34
from typing import Dict
45
from typing import List
56
from typing import Optional
@@ -80,19 +81,21 @@ async def from_sqs(
8081
)
8182
return [result for result in results if isinstance(result, cls)]
8283

83-
async def to_sqs(self, wait_time_in_seconds: int = None) -> None:
84+
def __send_kwargs(
85+
self, queue_url: str, wait_time_in_seconds: int = None
86+
) -> Dict[str, Any]:
8487
"""
85-
Send this object to SQS.
86-
Well set this object's message_id to the message id rom SQS
88+
Create the send kwargs
8789
8890
Args:
8991
wait_time_in_seconds (int, optional): The length of time, in seconds, for which to delay a specific message.
9092
Valid values: 0 to 900. Maximum: 15 minutes. Messages with a positive DelaySeconds value become
9193
available for processing after the delay period is finished. If you don't specify a value, the
9294
default value for the queue applies. Defaults to None. Greater than 0, less than or equal to 900
93-
"""
94-
queue = self.__get_queue()
9595
96+
Returns:
97+
Dict[str, Any]: send kwargs
98+
"""
9699
send_kwargs = {}
97100
if wait_time_in_seconds is not None:
98101
if wait_time_in_seconds < 0:
@@ -101,13 +104,31 @@ async def to_sqs(self, wait_time_in_seconds: int = None) -> None:
101104
wait_time_in_seconds = 900
102105
send_kwargs["DelaySeconds"] = wait_time_in_seconds
103106

104-
send_kwargs["QueueUrl"] = queue.queue_url
107+
send_kwargs["QueueUrl"] = queue_url
105108
send_kwargs["MessageBody"] = json.dumps(
106109
{
107110
"model": self.__class__.__qualname__.lower(),
108111
"message": self.dict(exclude_unset=True),
109112
}
110113
)
114+
return send_kwargs
115+
116+
async def to_sqs(self, wait_time_in_seconds: int = None) -> None:
117+
"""
118+
Send this object to SQS.
119+
Well set this object's message_id to the message id rom SQS
120+
121+
Args:
122+
wait_time_in_seconds (int, optional): The length of time, in seconds, for which to delay a specific message.
123+
Valid values: 0 to 900. Maximum: 15 minutes. Messages with a positive DelaySeconds value become
124+
available for processing after the delay period is finished. If you don't specify a value, the
125+
default value for the queue applies. Defaults to None. Greater than 0, less than or equal to 900
126+
"""
127+
queue = self.__get_queue()
128+
129+
send_kwargs = self.__send_kwargs(
130+
queue_url=queue.queue_url, wait_time_in_seconds=wait_time_in_seconds
131+
)
111132
async with queue.session.create_client("sqs", **queue.client_kwargs) as client:
112133
response = await client.send_message(**send_kwargs)
113134

pydantic_sqs/queue.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ def __init__(
6969
"""
7070
if session is None:
7171
session = get_session()
72+
7273
super().__init__(
7374
queue_url=queue_url,
7475
aws_region=aws_region,
@@ -109,9 +110,9 @@ def client_kwargs(self) -> Dict[str, Any]:
109110

110111
def __recv_kwargs(
111112
self,
112-
max_messages: Optional[int],
113-
visibility_timeout: Optional[int],
114-
wait_time_seconds: Optional[int],
113+
max_messages: Optional[int] = None,
114+
visibility_timeout: Optional[int] = None,
115+
wait_time_seconds: Optional[int] = None,
115116
) -> Dict[str, Any]:
116117
"""
117118
__recv_kwargs - Get kwargs for recieving from sqs
@@ -166,11 +167,11 @@ async def from_sqs(
166167
ignore_empty (bool, optional): Whether or not to ignore an empty queue. Defaults to False. If True,
167168
an empty queue will return an empty list and not raise a MsgNotFoundError
168169
ignore_unknown (bool, optional): Whether or not to ignore unknown messages. Defaults to False.
169-
If true, unknown messages will not raise an InvaidMessageInQueueError and will simply return to the
170+
If true, unknown messages will not raise an InvalidMessageInQueueError and will simply return to the
170171
queue after their visibility timeout
171172
Raises:
172173
exceptions.MsgNotFoundError: If no messages are found in the queue
173-
exceptions.InvaidMessageInQueueError: If an unknown message is found in the queue.
174+
exceptions.InvalidMessageInQueueError: If an unknown message is found in the queue.
174175
175176
Returns:
176177
list[SQSModel]: A list of SQSModels from the queue
@@ -184,33 +185,34 @@ async def from_sqs(
184185
to_return = []
185186

186187
try:
187-
messages = await self.__get_messages(recv_kwargs)
188-
except exceptions.MsgNotFoundError:
188+
messages = await self._get_messages(recv_kwargs)
189+
except exceptions.MsgNotFoundError as exc:
189190
if ignore_empty:
190191
messages = []
191192
else:
192-
raise
193-
except exceptions.InvaidMessageInQueueError:
194-
if ignore_unknown:
195-
messages = []
196-
else:
197-
raise
193+
raise exc
194+
198195
for msg in messages:
199196
try:
200197
this_object = json.loads(msg["Body"])
198+
to_return.append(
199+
self.__message_to_object(
200+
message=this_object,
201+
message_id=msg["MessageId"],
202+
receipt_handle=msg["ReceiptHandle"],
203+
attributes=msg.get("Attributes", None),
204+
)
205+
)
201206
except json.JSONDecodeError as exc:
207+
if ignore_unknown:
208+
continue
202209
raise exceptions.InvalidMessageInQueueError(
203210
f"Message {msg['MessageId']} is not valid JSON"
204211
) from exc
205-
206-
to_return.append(
207-
self.__message_to_object(
208-
message=this_object,
209-
message_id=msg["MessageId"],
210-
receipt_handle=msg["ReceiptHandle"],
211-
attributes=msg.get("Attributes", None),
212-
)
213-
)
212+
except exceptions.InvalidMessageInQueueError as exc:
213+
if ignore_unknown:
214+
continue
215+
raise exc
214216

215217
return to_return
216218

@@ -228,15 +230,15 @@ def __message_to_object(
228230
message (dict[str, Any]): _description_
229231
230232
Raises:
231-
exceptions.InvaidMessageInQueueError: _description_
233+
exceptions.InvalidMessageInQueueError: _description_
232234
233235
Returns:
234236
SQSModel: _description_
235237
"""
236238
try:
237239
model = self.models[message["model"]]
238240
except KeyError:
239-
raise exceptions.InvaidMessageInQueueError(
241+
raise exceptions.InvalidMessageInQueueError(
240242
f"No model registered to queue {self.queue_url} for model "
241243
+ f"type {message['model']} from {message_id}"
242244
) from None
@@ -249,11 +251,11 @@ def __message_to_object(
249251
**message["message"],
250252
)
251253
except ValidationError as exc:
252-
raise exceptions.InvaidMessageInQueueError(
254+
raise exceptions.InvalidMessageInQueueError(
253255
f"Invalid message {message_id} from queue {self.queue_url}"
254256
) from exc
255257

256-
async def __get_messages(
258+
async def _get_messages(
257259
self,
258260
recv_kwargs: Dict[str, Any],
259261
) -> List[Dict[str, Any]]:
@@ -272,6 +274,8 @@ async def __get_messages(
272274
async with self.session.create_client("sqs", **self.client_kwargs) as client:
273275
response = await client.receive_message(**recv_kwargs)
274276

275-
if "Messages" not in response:
276-
raise exceptions.MsgNotFoundError(f"{self.queue_url} is empty")
277-
return response["Messages"]
277+
messages = response.get("Messages", [response.get("Message", None)])
278+
if messages[0] is None:
279+
raise exceptions.MsgNotFoundError(f"{self.queue_url} is empty")
280+
281+
return messages

test/conftest.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import os
22
import random
33
import string
4-
import time
54

65
import docker
7-
import pytest
86
import pytest_asyncio
9-
from aiobotocore.session import AioSession
107
from aiobotocore.session import get_session
118
from pydantic_sqs import SQSQueue
129

test/test_pydantic_SQSModel.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1+
import pytest
12
from pydantic_sqs import exceptions
23
from pydantic_sqs import SQSModel
3-
from pydantic_sqs import SQSQueue
4-
5-
import pytest
6-
import pytest_asyncio
7-
from aiobotocore.session import get_session
84

95

106
@pytest.mark.asyncio
@@ -166,3 +162,42 @@ class ThatModel(SQSModel):
166162

167163
from_sqs = await queue.from_sqs(max_messages=5)
168164
assert len(from_sqs) == 2
165+
166+
167+
def test_send_kwargs(localstack_queue):
168+
class ThisModel(SQSModel):
169+
test: str
170+
171+
queue = localstack_queue[0]
172+
queue.register_model(ThisModel)
173+
this_model = ThisModel(test="test")
174+
175+
kw_args = this_model._SQSModel__send_kwargs(queue_url=queue.queue_url)
176+
177+
assert "DelaySeconds" not in kw_args
178+
assert kw_args["QueueUrl"] == queue.queue_url
179+
assert isinstance(kw_args["MessageBody"], str)
180+
181+
182+
def test_send_kwargs_wait_time(localstack_queue):
183+
class ThisModel(SQSModel):
184+
test: str
185+
186+
queue = localstack_queue[0]
187+
queue.register_model(ThisModel)
188+
this_model = ThisModel(test="test")
189+
190+
# less than 0 becomes 0
191+
assert (
192+
this_model._SQSModel__send_kwargs(
193+
queue_url=queue.queue_url, wait_time_in_seconds=-1
194+
)["DelaySeconds"]
195+
== 0
196+
)
197+
# greater than 900 becomes 900
198+
assert (
199+
this_model._SQSModel__send_kwargs(
200+
queue_url=queue.queue_url, wait_time_in_seconds=901
201+
)["DelaySeconds"]
202+
== 900
203+
)

0 commit comments

Comments
 (0)