Skip to content

Commit c856fbe

Browse files
yannhamfricklerhandwerk
authored andcommitted
refactor: use pydantic models for logs
1 parent e953674 commit c856fbe

File tree

2 files changed

+44
-44
lines changed

2 files changed

+44
-44
lines changed

src/shared/logs/logs.py

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
from datetime import datetime
3-
from typing import Any, Literal, TypedDict
3+
from typing import Any, Literal
44

55
from django.contrib.auth.models import User
66
from django.contrib.postgres.aggregates import ArrayAgg
@@ -16,6 +16,7 @@
1616
)
1717
from django.db.models.functions import Cast, Coalesce, Concat, JSONObject, Replace
1818
from pghistory.models import EventQuerySet
19+
from pydantic import BaseModel
1920

2021
from shared.models import (
2122
CVEDerivationClusterProposalStatusEvent, # type: ignore
@@ -25,7 +26,7 @@
2526
logger = logging.getLogger(__name__)
2627

2728

28-
class ChangeEvent(TypedDict):
29+
class ChangeEvent(BaseModel):
2930
"""
3031
The common structure of a suggestion change event (except the `action`
3132
field, which is omitted here because of a Pydantic limitation: we want to
@@ -41,7 +42,7 @@ class ChangeEvent(TypedDict):
4142
username: str
4243

4344

44-
class PackageData(TypedDict):
45+
class PackageData(BaseModel):
4546
"""
4647
A package in a package change event.
4748
"""
@@ -115,15 +116,13 @@ def _annotate_username(self, query: EventQuerySet) -> EventQuerySet:
115116
)
116117

117118
def get_raw_events(
118-
self, suggestion_ids: list[str | None]
119+
self, suggestion_ids: list[int | None]
119120
) -> list[PackageChangeEvent | SuggestionChangeEvent]:
120121
"""
121122
Combine the different types of events related to a list of suggestions
122123
in a single list and order them by timestamp. Multiple log entries
123124
constituting one logical edit from the user aren't aggregated in this
124125
method. This is left to `get_dict`.
125-
126-
See `get_dict` for the schema of the output.
127126
"""
128127

129128
raw_events = []
@@ -141,13 +140,13 @@ def get_raw_events(
141140

142141
for status_event in status_qs.all().iterator():
143142
raw_events.append(
144-
{
145-
"suggestion_id": status_event.pgh_obj_id,
146-
"timestamp": status_event.pgh_created_at,
147-
"username": status_event.username,
148-
"action": status_event.pgh_label,
149-
"status_value": status_event.status,
150-
}
143+
SuggestionChangeEvent(
144+
suggestion_id=status_event.pgh_obj_id,
145+
timestamp=status_event.pgh_created_at,
146+
username=status_event.username,
147+
action=status_event.pgh_label,
148+
status_value=status_event.status,
149+
)
151150
)
152151

153152
package_qs = self._annotate_username(
@@ -182,21 +181,21 @@ def get_raw_events(
182181

183182
for package_event in package_qs.all().iterator():
184183
raw_events.append(
185-
{
186-
"suggestion_id": package_event.proposal_id,
187-
"timestamp": package_event.pgh_created_at,
188-
"username": package_event.username,
189-
"action": package_event.pgh_label,
190-
"package_names": package_event.package_names,
191-
"package_count": package_event.package_count,
192-
}
184+
PackageChangeEvent(
185+
suggestion_id=package_event.proposal_id,
186+
timestamp=package_event.pgh_created_at,
187+
username=package_event.username,
188+
action=package_event.pgh_label,
189+
package_names=package_event.package_names,
190+
package_count=package_event.package_count,
191+
)
193192
)
194193

195-
return sorted(raw_events, key=lambda event: event["timestamp"])
194+
return sorted(raw_events, key=lambda event: event.timestamp)
196195

197196
def get_dict(
198-
self, suggestion_ids: list[str | None]
199-
) -> dict[str | None, dict[str, Any]]:
197+
self, suggestion_ids: list[int | None]
198+
) -> dict[int, list[dict[str, Any]]]:
200199
"""
201200
Aggregate the different types of events related to a given suggestion in
202201
a unified list of dicts, ordered by timestamp and with bulk actions
@@ -205,10 +204,12 @@ def get_dict(
205204

206205
raw_events = self.get_raw_events(suggestion_ids)
207206

208-
grouped_activity_log = {}
207+
grouped_activity_log: dict[
208+
int, list[PackageChangeEvent | SuggestionChangeEvent]
209+
] = {}
209210

210211
for event in raw_events:
211-
suggestion_id = event.get("suggestion_id")
212+
suggestion_id = event.suggestion_id
212213

213214
if suggestion_id in grouped_activity_log:
214215
grouped_activity_log[suggestion_id].append(event)
@@ -217,38 +218,35 @@ def get_dict(
217218

218219
# Second pass to fold repeated package actions by user,
219220
# needed because with htmx we're sending item-wise changes that we still want to display in bulk
220-
folded_activity_log = {}
221+
folded_activity_log: dict[int, list[dict[str, Any]]] = {}
222+
221223
for suggestion_id, events in grouped_activity_log.items():
222-
suggestion_log = []
224+
suggestion_log: list[PackageChangeEvent | SuggestionChangeEvent] = []
223225

224226
accumulator = None
225227
for event in events:
226228
# Bulk events that are subject to folding are currently
227229
# - package editions
228230
# - maintainers editions (soon to be logged)
229-
if event["action"].startswith("derivations"):
231+
if event.action.startswith("derivations"):
230232
if not accumulator:
231233
accumulator = event
232234
else:
233235
if (
234-
event["action"] == accumulator["action"]
235-
and event["username"] == accumulator["username"]
236+
event.action == accumulator.action
237+
and event.username == accumulator.username
236238
):
237239
# For now, this is the only remaining possibility,
238240
# but we'll add maintainer edits soon.
239-
if event["action"].startswith("derivations"):
240-
accumulator["package_names"] = (
241-
accumulator["package_names"]
242-
+ event["package_names"]
241+
if event.action.startswith("derivations"):
242+
accumulator.package_names = (
243+
accumulator.package_names + event.package_names
243244
)
244-
accumulator["package_count"] = (
245-
accumulator["package_count"]
246-
+ event["package_count"]
245+
accumulator.package_count = (
246+
accumulator.package_count + event.package_count
247247
)
248-
249-
accumulator["timestamp"] = event[
250-
"timestamp"
251-
] # Keep latest timestamp
248+
# Keep latest timestamp
249+
accumulator.timestamp = event.timestamp
252250
else:
253251
suggestion_log.append(accumulator)
254252
accumulator = event
@@ -261,6 +259,8 @@ def get_dict(
261259
if accumulator:
262260
suggestion_log.append(accumulator)
263261

264-
folded_activity_log[suggestion_id] = suggestion_log
262+
folded_activity_log[suggestion_id] = [
263+
event.model_dump() for event in suggestion_log
264+
]
265265

266266
return folded_activity_log

src/webview/templatetags/viewutils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def last_entry(log: list) -> Any | None:
114114
@register.filter
115115
def versioned_package_name(package_entry: dict[str, Any]) -> str:
116116
_, version = parse_drv_name(package_entry["name"])
117-
return f"pkgs.{package_entry["attribute"]} {version}"
117+
return f"pkgs.{package_entry['attribute']} {version}"
118118

119119

120120
def is_admin(user: Any) -> bool:

0 commit comments

Comments
 (0)