11"""Models for the webiscite app"""
22
33import json
4+ import logging
45from collections .abc import Iterator
56from contextlib import contextmanager
6- from logging import getLogger
77from typing import Any
88
99from django .conf import settings
2020
2121from .constitution import is_constitutional
2222
23- logger = getLogger (__name__ )
23+ logger = logging . getLogger (__name__ )
2424
2525
2626class ClosedBillVoteError (Exception ):
@@ -53,8 +53,7 @@ def create_from_github(self, pr: dict[str, Any]) -> T:
5353 },
5454 )
5555
56- action = "created" if created else "updated"
57- logger .info ("PR %s: Pull request %s" , pr ["number" ], action )
56+ pull_request .log ("%s" , "Created" if created else "Updated" )
5857 return pull_request
5958
6059
@@ -86,6 +85,10 @@ class PullRequest(TimeStampedModel):
8685 def __str__ (self ) -> str :
8786 return f"PR #{ self .number } "
8887
88+ def log (self , msg , * args , level = logging .INFO ):
89+ logger .log (level , f"PR #%s: { msg } " , self .number , * args ) # noqa: G004
90+ # f-string necessary to let string interpolation work in msg
91+
8992 @property
9093 def diff_link (self ) -> str :
9194 """Return base url of PR by removing ".diff" extension"""
@@ -106,7 +109,7 @@ def close(self) -> "Bill | None":
106109 try :
107110 bill : Bill = self .bill_set .get (status = Bill .Status .OPEN )
108111 except Bill .DoesNotExist :
109- logger . info ( "PR %s: No open bill found", self . number )
112+ self . log ( " No open bill found" )
110113 return None
111114 else :
112115 bill .close ()
@@ -141,6 +144,7 @@ def get_queryset(self):
141144 return (
142145 super ()
143146 .get_queryset ()
147+ .select_related ("pull_request" )
144148 .annotate (
145149 total_votes = models .Count ("vote" ),
146150 yes_percent = models .Case (
@@ -203,7 +207,7 @@ def create_from_github(
203207 applicable
204208 """
205209 with self ._create_submit_task () as submit_task :
206- self ._bill = self .model (
210+ self ._bill : Bill = self .model (
207211 name = title ,
208212 description = body ,
209213 author = author ,
@@ -214,10 +218,10 @@ def create_from_github(
214218 )
215219 self ._bill .full_clean ()
216220 self ._bill .save ()
217- logger .info ("PR %s: Bill %s created" , pull_request .number , self ._bill .id )
218221 bill = self ._bill
222+ bill .log ("Created" )
219223
220- return bill # noqa: RET504
224+ return bill
221225
222226 @contextmanager
223227 def _create_submit_task (self ) -> Iterator [PeriodicTask ]:
@@ -255,12 +259,9 @@ def _create_submit_task(self) -> Iterator[PeriodicTask]:
255259 submit_task .name = f"bill_submit:{ self ._bill .id } "
256260 submit_task .args = json .dumps ([self ._bill .id ])
257261 submit_task .save ()
258- logger .info (
259- "PR %s: Scheduled %s" ,
260- self ._bill .pull_request .number ,
261- submit_task .name ,
262- )
262+ self ._bill .log ("Scheduled %s" , submit_task .name )
263263
264+ # Attribute could be shared between model instances
264265 del self ._bill
265266
266267
@@ -322,6 +323,10 @@ class Meta:
322323 def __str__ (self ) -> str :
323324 return f"Bill { self .id } : { self .name } ({ self .pull_request } )"
324325
326+ def log (self , msg , * args ):
327+ logger .info (f"Bill %s (#%s): { msg } " , self .id , self .pull_request .number , * args ) # noqa: G004
328+ # f-string necessary to let string interpolation work in msg
329+
325330 def get_absolute_url (self ) -> str :
326331 """Returns URL to view this Bill instance"""
327332 return reverse ("webiscite:bill-detail" , kwargs = {"pk" : self .id })
@@ -359,39 +364,21 @@ def vote(self, user: User, *, support: bool) -> None:
359364 if self .status != self .Status .OPEN :
360365 raise ClosedBillVoteError ("Bill is not open for voting" )
361366
367+ supports = "yes" if support else "no"
362368 try :
363369 vote : Vote = self .vote_set .get (user = user )
364370 if vote .support == support :
365371 vote .delete ()
366- logger .info (
367- 'PR %s: User %s retracted their vote "%s" on bill %s' ,
368- self .pull_request .number ,
369- user .username ,
370- "yes" if support else "no" ,
371- self .id ,
372- )
372+ self .log ("%s retracted their %s vote" , user .username , supports )
373373
374374 else :
375375 vote .support = support
376376 vote .save (update_fields = ["support" , "when" ]) # Ensure "when" is updated
377- logger .info (
378- "PR %s: User %s changed their vote on bill %s from %s to %s" ,
379- self .pull_request .number ,
380- user .username ,
381- self .id ,
382- not support ,
383- support ,
384- )
377+ self .log ("%s changed their vote to %s" , user .username , supports )
385378
386379 except Vote .DoesNotExist :
387380 self .votes .add (user , through_defaults = {"support" : support })
388- logger .info (
389- "PR %s: User %s voted %s on bill %s" ,
390- self .pull_request .number ,
391- user .username ,
392- "yes" if support else "no" ,
393- self .id ,
394- )
381+ self .log ("%s voted %s" , user .username , supports )
395382
396383 def user_supports (self , user : User ) -> bool | None :
397384 """
@@ -415,21 +402,17 @@ def close(self) -> None:
415402 """Close the bill and disable its submit task"""
416403 self .status = self .Status .CLOSED
417404 self .save ()
418- logger . info ( "Bill %s set to closed" , self . id )
405+ self . log ( "Closed" )
419406
420407 self ._submit_task .enabled = False
421408 self ._submit_task .save ()
422- logger . info ("Submit task for bill %s disabled" , self . id )
409+ self . log ("Submit task disabled" )
423410
424411 def submit (self ) -> None :
425412 """Check if the bill has enough votes to pass and update the status"""
426413 # Bill was closed before voting period ended
427414 if self .status != Bill .Status .OPEN :
428- logger .info (
429- "PR %s: bill %s was not open when submitted" ,
430- self .pull_request .number ,
431- self .id ,
432- )
415+ self .log ("Bill was not open when submitted" )
433416 return
434417
435418 self .status = self ._check_approval ()
@@ -438,11 +421,7 @@ def submit(self) -> None:
438421 def _check_approval (self ) -> "Bill.Status" :
439422 total_votes = self .votes .count ()
440423 if total_votes < settings .WEBISCITE_MINIMUM_QUORUM :
441- logger .info (
442- "PR %s: bill %s rejected due to insufficient votes" ,
443- self .pull_request .number ,
444- self .id ,
445- )
424+ self .log ("Rejected due to insufficient votes" )
446425 return self .Status .FAILED
447426
448427 approval = self .yes_votes .count () / total_votes
@@ -452,18 +431,8 @@ def _check_approval(self) -> "Bill.Status":
452431 approved = approval > settings .WEBISCITE_NORMAL_MAJORITY
453432
454433 if not approved :
455- logger .info (
456- "PR %s: bill %s rejected with %s%% approval" ,
457- self .pull_request .number ,
458- self .id ,
459- approval * 100 ,
460- )
434+ self .log ("Rejected with %s%% approval" , approval * 100 )
461435 return self .Status .REJECTED
462436
463- logger .info (
464- "PR %s: bill %s approved with %s%% approval" ,
465- self .pull_request .number ,
466- self .id ,
467- approval ,
468- )
437+ self .log ("Approved with %s%% approval" , approval * 100 )
469438 return self .Status .APPROVED
0 commit comments