Skip to content

Commit

Permalink
refactor: Enhance type annotations and documentation for Score action (
Browse files Browse the repository at this point in the history
  • Loading branch information
drikusroor authored Dec 23, 2024
1 parent ced2191 commit b954e91
Showing 1 changed file with 55 additions and 45 deletions.
100 changes: 55 additions & 45 deletions backend/experiment/actions/score.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import random
from typing import Optional, TypedDict

from django.utils.translation import gettext as _

Expand All @@ -7,86 +8,92 @@
from .base_action import BaseAction


class ScoreConfig(TypedDict):
"""
Configuration for the Score action
Args:
show_section: whether metadata of the previous section should be shown, often the title of the last played song
show_total_score: whether the total score should be shown in the view
"""

show_section: bool
show_total_score: bool


class Score(BaseAction):
"""
Provide data for a score view, presenting feedback to a participant after a Trial
Relates to client component: Score.ts
Provide data for a score view, presenting feedback to a participant after a Trial.
Args:
session: a Session object
title: the title of the score page
result: the result for which section and/or score should be reported
score: the score to report, will override result.score
session (Session): a Session object
title (str): the title of the score page
result (Optional[Result]): the result for which section and/or score should be reported
score (Optional[float]): the score to report, will override result.score
score_message: a function which constructs feedback text based on the score
config: a dict with the following settings:
- show_section: whether metadata of the previous section should be shown
- show_total_score: whether the total score should be shown
icon: the name of a themify-icon shown with the view or None
timer: int or None. If int, wait for as many seconds until showing the next view
feedback: An additional feedback text
config (Optional[ScoreConfig]): a dict with the following settings:
icon (Optional[str]): the name of a themify-icon shown with the view or None
timer (Optional[int]): int or None. If int, wait for as many seconds until showing the next view
feedback (Optional[str]): An additional feedback text
Note:
Relates to the Score.tsx component in the frontend
"""

ID = 'SCORE'
ID = "SCORE"

def __init__(
self,
session: Session,
title: str = '',
result: Result = None,
score: float = None,
score_message: str = '',
config: dict = {},
icon: str = None,
timer: int = None,
feedback: str = None,
title: str = "",
result: Optional[Result] = None,
score: Optional[float] = None,
score_message: str = "",
config: Optional[ScoreConfig] = None,
icon: Optional[str] = None,
timer: Optional[int] = None,
feedback: Optional[str] = None,
):
self.title = title or _('Round {get_rounds_passed} / {total_rounds}').format(
self.title = title or _("Round {get_rounds_passed} / {total_rounds}").format(
get_rounds_passed=session.get_rounds_passed(),
total_rounds=session.block.rounds,
)
self.session = session
self.score = self.get_score(score, result)
self.score_message = score_message or self.default_score_message(self.score)
self.feedback = feedback
self.config = {
'show_section': False,
'show_total_score': False
}
self.config = {"show_section": False, "show_total_score": False}
if config:
self.config.update(config)
self.icon = icon
self.texts = {
'score': _('Total Score'),
'next': _('Next'),
'listen_explainer': _('You listened to:')
}
self.texts = {"score": _("Total Score"), "next": _("Next"), "listen_explainer": _("You listened to:")}
self.last_song = result.section.song_label() if result else session.last_song()
self.timer = timer

def action(self) -> dict:
"""Serialize score data
Returns:
dictionary with the relevant data for the Score.ts view
dictionary with the relevant data for the Score.tsx view
"""
# Create action
action = {
'view': self.ID,
'title': self.title,
'score': self.score,
'score_message': self.score_message,
'texts': self.texts,
'feedback': self.feedback,
'icon': self.icon,
'timer': self.timer,
"view": self.ID,
"title": self.title,
"score": self.score,
"score_message": self.score_message,
"texts": self.texts,
"feedback": self.feedback,
"icon": self.icon,
"timer": self.timer,
}
if self.config['show_section']:
action['last_song'] = self.last_song
if self.config['show_total_score']:
action['total_score'] = self.session.total_score()
if self.config["show_section"]:
action["last_song"] = self.last_song
if self.config["show_total_score"]:
action["total_score"] = self.session.total_score()
return action

def get_score(self, score: float = None, result: Result = None) -> float:
def get_score(self, score: Optional[float] = None, result: Optional[Result] = None) -> float:
"""Retrieve the last relevant score, fall back to session.last_score() if neither score nor result are defined
Args:
Expand All @@ -105,13 +112,16 @@ def default_score_message(self, score):
# None
if score is None:
score = 0

# Zero
if score == 0:
# "Too bad!", "Come on!", "Try another!", "Try again!"
return random.choice([_("No points")])

# Negative
if score < 0:
return random.choice([_("Incorrect")]) # "Too bad!", "Fail!", "Nooo!"

# Positive
# "Well done!", "Nice job!", "Great one!", "Score!", "You're good!", "Awesome!", "Nice one!"
return random.choice([_("Correct")])

0 comments on commit b954e91

Please sign in to comment.