Skip to content

Commit 70bb8d1

Browse files
committed
Make it work with new ruff and mypy requirements
1 parent f4a6f5b commit 70bb8d1

File tree

8 files changed

+86
-91
lines changed

8 files changed

+86
-91
lines changed

src/firetower/auth/tests/test_services.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from unittest.mock import MagicMock, patch
1+
from unittest.mock import patch
22

33
import pytest
44
from django.contrib.auth.models import User

src/firetower/incidents/admin.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import Any
44

55
from django.contrib import admin
6-
from django.db.models import ForeignKey, ManyToManyField
6+
from django.db.models import ForeignKey, ManyToManyField, QuerySet
77
from django.forms import ModelChoiceField, ModelMultipleChoiceField
88
from django.http import HttpRequest
99

@@ -72,17 +72,19 @@ def incident_number_display(self, obj: Incident) -> str:
7272
incident_number_display.admin_order_field = "id"
7373

7474
@admin.action(description="Sync participants from Slack")
75-
def sync_participants_from_slack(self, request, queryset):
75+
def sync_participants_from_slack(
76+
self, request: HttpRequest, queryset: QuerySet[Incident]
77+
) -> None:
7678
success_count = 0
7779
skipped_count = 0
7880
error_count = 0
7981

8082
for incident in queryset:
8183
try:
8284
stats = sync_incident_participants_from_slack(incident, force=True)
83-
if stats["errors"]:
85+
if stats.errors:
8486
error_count += 1
85-
elif stats["skipped"]:
87+
elif stats.skipped:
8688
skipped_count += 1
8789
else:
8890
success_count += 1
Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
import logging
2+
from dataclasses import dataclass, field
23
from datetime import timedelta
34

5+
from django.conf import settings
46
from django.utils import timezone
57

68
from firetower.auth.services import get_or_create_user_from_slack_id
7-
from firetower.incidents.models import ExternalLinkType
9+
from firetower.incidents.models import ExternalLinkType, Incident
810
from firetower.integrations.services import SlackService
911

1012
logger = logging.getLogger(__name__)
1113
_slack_service = SlackService()
1214

1315

14-
def sync_incident_participants_from_slack(incident, force=False):
16+
@dataclass
17+
class ParticipantsSyncStats:
18+
"""Statistics from a participant sync operation."""
19+
20+
added: int = 0
21+
already_existed: int = 0
22+
errors: list[str] = field(default_factory=list)
23+
skipped: bool = False
24+
25+
26+
def sync_incident_participants_from_slack(
27+
incident: Incident, force: bool = False
28+
) -> ParticipantsSyncStats:
1529
"""
1630
Sync incident participants from Slack channel members.
1731
@@ -20,21 +34,9 @@ def sync_incident_participants_from_slack(incident, force=False):
2034
force: If True, bypass throttle and force sync
2135
2236
Returns:
23-
dict with sync stats: {
24-
"added": int,
25-
"already_existed": int,
26-
"errors": list[str],
27-
"skipped": bool,
28-
}
37+
ParticipantsSyncStats dataclass with sync statistics
2938
"""
30-
from django.conf import settings
31-
32-
stats = {
33-
"added": 0,
34-
"already_existed": 0,
35-
"errors": [],
36-
"skipped": False,
37-
}
39+
stats = ParticipantsSyncStats()
3840

3941
if not force and incident.participants_last_synced_at:
4042
time_since_sync = timezone.now() - incident.participants_last_synced_at
@@ -44,31 +46,31 @@ def sync_incident_participants_from_slack(incident, force=False):
4446
logger.info(
4547
f"Skipping sync for incident {incident.id} - synced {time_since_sync.total_seconds():.0f}s ago"
4648
)
47-
stats["skipped"] = True
49+
stats.skipped = True
4850
return stats
4951

5052
slack_link = incident.external_links.filter(type=ExternalLinkType.SLACK).first()
5153

5254
if not slack_link:
5355
error_msg = f"No Slack link found for incident {incident.id}"
5456
logger.warning(error_msg)
55-
stats["errors"].append(error_msg)
57+
stats.errors.append(error_msg)
5658
return stats
5759

5860
channel_id = _slack_service.parse_channel_id_from_url(slack_link.url)
5961

6062
if not channel_id:
6163
error_msg = f"Could not parse channel ID from URL: {slack_link.url}"
6264
logger.warning(error_msg)
63-
stats["errors"].append(error_msg)
65+
stats.errors.append(error_msg)
6466
return stats
6567

6668
slack_member_ids = _slack_service.get_channel_members(channel_id)
6769

6870
if slack_member_ids is None:
6971
error_msg = f"Failed to fetch channel members for {channel_id}"
7072
logger.error(error_msg)
71-
stats["errors"].append(error_msg)
73+
stats.errors.append(error_msg)
7274
return stats
7375

7476
logger.info(
@@ -88,14 +90,14 @@ def sync_incident_participants_from_slack(incident, force=False):
8890
if not user:
8991
error_msg = f"Could not get/create user for Slack ID: {slack_user_id}"
9092
logger.warning(error_msg)
91-
stats["errors"].append(error_msg)
93+
stats.errors.append(error_msg)
9294
continue
9395

9496
if user.id in existing_participant_ids:
95-
stats["already_existed"] += 1
97+
stats.already_existed += 1
9698
else:
9799
new_participants.append(user)
98-
stats["added"] += 1
100+
stats.added += 1
99101

100102
if new_participants:
101103
incident.participants.add(*new_participants)
@@ -107,8 +109,8 @@ def sync_incident_participants_from_slack(incident, force=False):
107109
incident.save(update_fields=["participants_last_synced_at"])
108110

109111
logger.info(
110-
f"Sync complete for incident {incident.id}: {stats['added']} added, "
111-
f"{stats['already_existed']} already existed, {len(stats['errors'])} errors"
112+
f"Sync complete for incident {incident.id}: {stats.added} added, "
113+
f"{stats.already_existed} already existed, {len(stats.errors)} errors"
112114
)
113115

114116
return stats

src/firetower/incidents/tests/test_admin.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from firetower.incidents.admin import IncidentAdmin
1010
from firetower.incidents.models import Incident, IncidentSeverity, IncidentStatus
11+
from firetower.incidents.services import ParticipantsSyncStats
1112

1213

1314
@pytest.mark.django_db
@@ -54,12 +55,10 @@ def test_sync_participants_action_calls_sync_function(self):
5455
with patch(
5556
"firetower.incidents.admin.sync_incident_participants_from_slack"
5657
) as mock_sync:
57-
mock_sync.return_value = {
58-
"added": 5,
59-
"already_existed": 2,
60-
"errors": [],
61-
"skipped": False,
62-
}
58+
mock_sync.return_value = ParticipantsSyncStats(
59+
added=5,
60+
already_existed=2,
61+
)
6362

6463
self.incident_admin.sync_participants_from_slack(request, queryset)
6564

@@ -97,19 +96,14 @@ def test_sync_participants_action_reports_stats(self):
9796

9897
def side_effect(incident, force):
9998
if incident.id == incident1.id:
100-
return {
101-
"added": 5,
102-
"already_existed": 2,
103-
"errors": [],
104-
"skipped": False,
105-
}
99+
return ParticipantsSyncStats(
100+
added=5,
101+
already_existed=2,
102+
)
106103
elif incident.id == incident2.id:
107-
return {
108-
"added": 0,
109-
"already_existed": 0,
110-
"errors": ["Some error"],
111-
"skipped": False,
112-
}
104+
return ParticipantsSyncStats(
105+
errors=["Some error"],
106+
)
113107
else:
114108
raise Exception("Sync failed")
115109

src/firetower/incidents/tests/test_services.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ def test_syncs_participants_from_slack_channel(self):
6868

6969
stats = sync_incident_participants_from_slack(incident)
7070

71-
assert stats["added"] == 2
72-
assert stats["already_existed"] == 0
73-
assert stats["errors"] == []
74-
assert stats["skipped"] is False
71+
assert stats.added == 2
72+
assert stats.already_existed == 0
73+
assert stats.errors == []
74+
assert stats.skipped is False
7575

7676
assert incident.participants.count() == 3
7777
assert slack_user1 in incident.participants.all()
@@ -139,8 +139,8 @@ def test_throttle_skips_recent_sync(self):
139139

140140
stats = sync_incident_participants_from_slack(incident)
141141

142-
assert stats["skipped"] is True
143-
assert stats["added"] == 0
142+
assert stats.skipped is True
143+
assert stats.added == 0
144144

145145
def test_force_bypasses_throttle(self):
146146
incident = Incident.objects.create(
@@ -177,8 +177,8 @@ def test_force_bypasses_throttle(self):
177177

178178
stats = sync_incident_participants_from_slack(incident, force=True)
179179

180-
assert stats["skipped"] is False
181-
assert stats["added"] == 1
180+
assert stats.skipped is False
181+
assert stats.added == 1
182182

183183
def test_handles_missing_slack_link(self):
184184
incident = Incident.objects.create(
@@ -189,9 +189,9 @@ def test_handles_missing_slack_link(self):
189189

190190
stats = sync_incident_participants_from_slack(incident)
191191

192-
assert stats["added"] == 0
193-
assert len(stats["errors"]) == 1
194-
assert "No Slack link" in stats["errors"][0]
192+
assert stats.added == 0
193+
assert len(stats.errors) == 1
194+
assert "No Slack link" in stats.errors[0]
195195

196196
def test_handles_invalid_channel_url(self):
197197
incident = Incident.objects.create(
@@ -212,9 +212,9 @@ def test_handles_invalid_channel_url(self):
212212

213213
stats = sync_incident_participants_from_slack(incident)
214214

215-
assert stats["added"] == 0
216-
assert len(stats["errors"]) == 1
217-
assert "Could not parse channel ID" in stats["errors"][0]
215+
assert stats.added == 0
216+
assert len(stats.errors) == 1
217+
assert "Could not parse channel ID" in stats.errors[0]
218218

219219
def test_handles_slack_api_failure(self):
220220
incident = Incident.objects.create(
@@ -240,9 +240,9 @@ def test_handles_slack_api_failure(self):
240240

241241
stats = sync_incident_participants_from_slack(incident)
242242

243-
assert stats["added"] == 0
244-
assert len(stats["errors"]) == 1
245-
assert "Failed to fetch channel members" in stats["errors"][0]
243+
assert stats.added == 0
244+
assert len(stats.errors) == 1
245+
assert "Failed to fetch channel members" in stats.errors[0]
246246

247247
def test_handles_user_creation_failure(self):
248248
incident = Incident.objects.create(
@@ -273,9 +273,9 @@ def test_handles_user_creation_failure(self):
273273

274274
stats = sync_incident_participants_from_slack(incident)
275275

276-
assert stats["added"] == 0
277-
assert len(stats["errors"]) == 1
278-
assert "Could not get/create user" in stats["errors"][0]
276+
assert stats.added == 0
277+
assert len(stats.errors) == 1
278+
assert "Could not get/create user" in stats.errors[0]
279279

280280
def test_counts_already_existed_participants(self):
281281
incident = Incident.objects.create(
@@ -312,8 +312,8 @@ def test_counts_already_existed_participants(self):
312312

313313
stats = sync_incident_participants_from_slack(incident)
314314

315-
assert stats["added"] == 0
316-
assert stats["already_existed"] == 1
315+
assert stats.added == 0
316+
assert stats.already_existed == 1
317317
assert incident.participants.count() == 1
318318

319319
def test_skips_bots(self):
@@ -357,5 +357,5 @@ def test_skips_bots(self):
357357

358358
assert mock_get_user.call_count == 1
359359
mock_get_user.assert_called_once_with("U11111")
360-
assert stats["added"] == 1
361-
assert stats["errors"] == []
360+
assert stats.added == 1
361+
assert stats.errors == []

src/firetower/incidents/tests/test_views.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Tag,
1515
TagType,
1616
)
17+
from firetower.incidents.services import ParticipantsSyncStats
1718

1819

1920
@pytest.mark.django_db
@@ -323,12 +324,10 @@ def test_sync_participants_endpoint(self):
323324
with patch(
324325
"firetower.incidents.views.sync_incident_participants_from_slack"
325326
) as mock_sync:
326-
mock_sync.return_value = {
327-
"added": 3,
328-
"already_existed": 5,
329-
"errors": [],
330-
"skipped": False,
331-
}
327+
mock_sync.return_value = ParticipantsSyncStats(
328+
added=3,
329+
already_existed=5,
330+
)
332331

333332
self.client.force_authenticate(user=self.user)
334333
response = self.client.post(

0 commit comments

Comments
 (0)