diff --git a/backend/experiment/forms.py b/backend/experiment/forms.py index 874147d33..0f9350abe 100644 --- a/backend/experiment/forms.py +++ b/backend/experiment/forms.py @@ -1,6 +1,6 @@ from django.forms import CheckboxSelectMultiple, ModelForm, ChoiceField, Form, MultipleChoiceField, ModelMultipleChoiceField, Select, TypedMultipleChoiceField, CheckboxSelectMultiple, TextInput from experiment.models import ExperimentCollection, Block, SocialMediaConfig -from experiment.rules import EXPERIMENT_RULES +from experiment.rules import BLOCK_RULES # session_keys for Export CSV @@ -155,8 +155,8 @@ def __init__(self, *args, **kwargs): super(ModelForm, self).__init__(*args, **kwargs) choices = tuple() - for i in EXPERIMENT_RULES: - choices += ((i, EXPERIMENT_RULES[i].__name__),) + for i in BLOCK_RULES: + choices += ((i, BLOCK_RULES[i].__name__),) choices += (("", "---------"),) self.fields['rules'] = ChoiceField( @@ -171,7 +171,7 @@ def clean_playlists(self): # Validat the rules' playlist rule_id = self.cleaned_data['rules'] - cl = EXPERIMENT_RULES[rule_id] + cl = BLOCK_RULES[rule_id] rules = cl() playlists = self.cleaned_data['playlists'] diff --git a/backend/experiment/management/commands/compileplaylist.py b/backend/experiment/management/commands/compileplaylist.py index f6a189aae..7646f6c61 100644 --- a/backend/experiment/management/commands/compileplaylist.py +++ b/backend/experiment/management/commands/compileplaylist.py @@ -9,7 +9,7 @@ from django.core.management.base import BaseCommand, CommandError from django.conf import settings -from experiment.rules import EXPERIMENT_RULES +from experiment.rules import BLOCK_RULES class Command(BaseCommand): @@ -63,7 +63,7 @@ def handle(self, *args, **options): artist_name = song_names[audio_file_clean] song_name = basename(audio_file)[:-4] elif experiment_option: - rules = EXPERIMENT_RULES.get(experiment_option) + rules = BLOCK_RULES.get(experiment_option) info = rules.get_info_playlist(rules, audio_file_clean) artist_name = info.get('artist') song_name = info.get('song') diff --git a/backend/experiment/management/commands/createruleset.py b/backend/experiment/management/commands/createruleset.py index d2455ea46..7342fbfa3 100644 --- a/backend/experiment/management/commands/createruleset.py +++ b/backend/experiment/management/commands/createruleset.py @@ -39,8 +39,8 @@ def create_experiment_rule_class(self, ruleset_name): with open('./experiment/management/commands/templates/experiment.py', 'r') as template: f.write(template.read() .replace('NewExperimentRuleset', ruleset_name_pascal_case) - .replace('new_experiment_ruleset', ruleset_name_snake_case) - .replace('NEW_EXPERIMENT_RULESET', ruleset_name_snake_case_upper) + .replace('new_block_ruleset', ruleset_name_snake_case) + .replace('NEW_BLOCK_RULESET', ruleset_name_snake_case_upper) .replace('New Experiment Ruleset', ruleset_name.title()) ) @@ -64,8 +64,8 @@ def register_experiment_rule(self, ruleset_name, file_path): import_index = next(i for i, line in enumerate(lines) if line.startswith('from .') and line > new_import) lines.insert(import_index, new_import) - # Find the line to insert the new dictionary entry, maintaining alphabetical order within the EXPERIMENT_RULES - dict_start_index = lines.index("EXPERIMENT_RULES = {\n") + 1 # Start after the opening brace + # Find the line to insert the new dictionary entry, maintaining alphabetical order within the BLOCK_RULES + dict_start_index = lines.index("BLOCK_RULES = {\n") + 1 # Start after the opening brace dict_end_index = lines.index("}\n", dict_start_index) # Find the closing brace dict_entry_index = next((i for i, line in enumerate(lines[dict_start_index:dict_end_index], dict_start_index) if line > new_dict_entry), dict_end_index) lines.insert(dict_entry_index, new_dict_entry) @@ -93,8 +93,8 @@ def create_test_file(self, ruleset_name): with open('./experiment/management/commands/templates/test_experiment.py', 'r') as template: f.write(template.read() .replace('NewExperimentRuleset', ruleset_name_pascal_case) - .replace('new_experiment_ruleset', ruleset_name_snake_case) - .replace('NEW_EXPERIMENT_RULESET', ruleset_name_snake_case_upper) + .replace('new_block_ruleset', ruleset_name_snake_case) + .replace('NEW_BLOCK_RULESET', ruleset_name_snake_case_upper) .replace('New Experiment Ruleset', ruleset_name.title()) ) diff --git a/backend/experiment/management/commands/templates/experiment.py b/backend/experiment/management/commands/templates/experiment.py index b1e7f8366..55e22d631 100644 --- a/backend/experiment/management/commands/templates/experiment.py +++ b/backend/experiment/management/commands/templates/experiment.py @@ -12,7 +12,7 @@ class NewExperimentRuleset(Base): ''' An experiment type that could be used to test musical preferences ''' - ID = 'NEW_EXPERIMENT_RULESET' + ID = 'NEW_BLOCK_RULESET' contact_email = 'info@example.com' def __init__(self): @@ -33,7 +33,7 @@ def __init__(self): ] def first_round(self, experiment): - ''' Provide the first rounds of the experiment, + ''' Provide the first rounds of the experiment, before session creation The first_round must return at least one Info or Explainer action Consent and Playlist are often desired, but optional @@ -41,9 +41,9 @@ def first_round(self, experiment): # 1. Informed consent (optional) consent = Consent(experiment.consent, title=_('Informed consent'), - confirm=_('I agree'), + confirm=_('I agree'), deny=_('Stop')) - + # 2. Choose playlist (optional, only relevant if there are multiple playlists the participant can choose from) playlist = Playlist(experiment.playlists.all()) @@ -57,13 +57,13 @@ def first_round(self, experiment): ], step_numbers=True ) - + return [ consent, playlist, explainer ] - + def next_round(self, session): # ask any questions defined in the admin interface actions = self.get_questionnaire(session) @@ -109,4 +109,3 @@ def get_trial(self, session): } ) return view - \ No newline at end of file diff --git a/backend/experiment/migrations/0018_set_default_question_data.py b/backend/experiment/migrations/0018_set_default_question_data.py index aa293e6ee..ea6066e52 100644 --- a/backend/experiment/migrations/0018_set_default_question_data.py +++ b/backend/experiment/migrations/0018_set_default_question_data.py @@ -1,11 +1,11 @@ from django.db import migrations -from experiment.rules import EXPERIMENT_RULES +from experiment.rules import BLOCK_RULES as EXPERIMENT_RULES def set_default_question_data(apps, schema_editor): Experiment = apps.get_model("experiment", "Experiment") - + for experiment in Experiment.objects.all(): experiment.questions = [q.key for q in EXPERIMENT_RULES[experiment.rules]().questions] experiment.save() diff --git a/backend/experiment/migrations/0036_add_question_model_data.py b/backend/experiment/migrations/0036_add_question_model_data.py index 34ea8d7b1..ebaba6b0d 100644 --- a/backend/experiment/migrations/0036_add_question_model_data.py +++ b/backend/experiment/migrations/0036_add_question_model_data.py @@ -1,7 +1,7 @@ from django.db import migrations from experiment.models import Block as Experiment -from experiment.rules import EXPERIMENT_RULES +from experiment.rules import BLOCK_RULES as EXPERIMENT_RULES def add_default_question_series(apps, schema_editor): diff --git a/backend/experiment/models.py b/backend/experiment/models.py index 088364c02..2917d83b8 100644 --- a/backend/experiment/models.py +++ b/backend/experiment/models.py @@ -286,12 +286,12 @@ def export_table(self, session_keys: List[str], result_keys: List[str], export_o def get_rules(self): """Get instance of rules class to be used for this session""" - from experiment.rules import EXPERIMENT_RULES + from experiment.rules import BLOCK_RULES - if self.rules not in EXPERIMENT_RULES: + if self.rules not in BLOCK_RULES: raise ValueError(f"Rules do not exist (anymore): {self.rules} for block {self.name} ({self.slug})") - cl = EXPERIMENT_RULES[self.rules] + cl = BLOCK_RULES[self.rules] return cl() def max_score(self): @@ -305,9 +305,9 @@ def max_score(self): def add_default_question_series(self): """ Add default question_series to block""" - from experiment.rules import EXPERIMENT_RULES + from experiment.rules import BLOCK_RULES from question.models import Question, QuestionSeries, QuestionInSeries - question_series = getattr(EXPERIMENT_RULES[self.rules](), "question_series", None) + question_series = getattr(BLOCK_RULES[self.rules](), "question_series", None) if question_series: for i, question_series in enumerate(question_series): qs = QuestionSeries.objects.create( diff --git a/backend/experiment/rules/__init__.py b/backend/experiment/rules/__init__.py index 9f515d37c..cf1e72c60 100644 --- a/backend/experiment/rules/__init__.py +++ b/backend/experiment/rules/__init__.py @@ -42,7 +42,7 @@ # If you create new Rules, add them to the list # so they can be referred to by the admin -EXPERIMENT_RULES = { +BLOCK_RULES = { Anisochrony.ID: Anisochrony, BeatAlignment.ID: BeatAlignment, BST.ID: BST, diff --git a/backend/experiment/rules/tafc.py b/backend/experiment/rules/tafc.py index d027d69a3..4651d280e 100644 --- a/backend/experiment/rules/tafc.py +++ b/backend/experiment/rules/tafc.py @@ -47,7 +47,7 @@ class TwoAlternativeForced(Base): # Add to __init.py__ file in the same directory as the current file: # from .tafc import TwoAlternativeForced - # To EXPERIMENT_RULES dictionary in __init.py__ + # To BLOCK_RULES dictionary in __init.py__ # TwoAlternativeForced.ID: TwoAlternativeForced ID = 'TWO_ALTERNATIVE_FORCED' @@ -90,7 +90,7 @@ def next_round(self, session): if actions: return actions - if session.rounds_passed() == 0: + if session.rounds_passed() == 0: # Beginning of experiment, return an explainer and the next trial action, no feedback on previous trial explainer2 = Explainer( @@ -104,13 +104,13 @@ def next_round(self, session): # Combine two actions, feedback on previous action and next trial action return [self.get_feedback(session), self.next_trial_action(session)] - else: + else: # All sections have been played, finalize the experiment and return feedback session.finish() session.save() return [self.get_feedback(session), self.get_final_view(session)] - + def next_trial_action(self, session): """ Returns the next trial action for the experiment. Not necessary as a separate method, but often used for convenience. diff --git a/backend/experiment/rules/tests/test_duration_discrimination.py b/backend/experiment/rules/tests/test_duration_discrimination.py index 66aa42694..d509faf67 100644 --- a/backend/experiment/rules/tests/test_duration_discrimination.py +++ b/backend/experiment/rules/tests/test_duration_discrimination.py @@ -21,7 +21,7 @@ def setUpTestData(cls): participant=cls.participant, playlist=cls.playlist ) - cls.rules = cls.session.experiment_rules() + cls.rules = cls.session.block_rules() def test_trial_action(self): difference = 200000 @@ -53,8 +53,8 @@ def setUpTestData(cls): participant=cls.participant, playlist=cls.playlist ) - cls.rules = cls.session.experiment_rules() - + cls.rules = cls.session.block_rules() + def test_trial_action(self): difficulty = 1001 catch_section = Section.objects.get(playlist=self.playlist.id, song__name=0) diff --git a/backend/experiment/rules/tests/test_hbat.py b/backend/experiment/rules/tests/test_hbat.py index 5656276f1..e73725700 100644 --- a/backend/experiment/rules/tests/test_hbat.py +++ b/backend/experiment/rules/tests/test_hbat.py @@ -22,8 +22,8 @@ def setUpTestData(cls): participant=cls.participant, playlist=cls.playlist ) - cls.rules = cls.session.experiment_rules() - + cls.rules = cls.session.block_rules() + def test_trial_action(self): level = 4 slower_trial = self.rules.next_trial_action(self.session, 1, level) @@ -54,8 +54,8 @@ def setUpTestData(cls): participant=cls.participant, playlist=cls.playlist ) - cls.rules = cls.session.experiment_rules() - + cls.rules = cls.session.block_rules() + def test_trial_action(self): in2 = self.rules.next_trial_action(self.session, 1, 3) assert in2 @@ -68,4 +68,4 @@ def test_trial_action(self): result_id = in3.feedback_form.form[0].result_id result = Result.objects.get(pk=result_id) assert result - assert result.expected_response == 'in3' \ No newline at end of file + assert result.expected_response == 'in3' diff --git a/backend/experiment/rules/tests/test_hooked.py b/backend/experiment/rules/tests/test_hooked.py index c398991d1..0430ee0f3 100644 --- a/backend/experiment/rules/tests/test_hooked.py +++ b/backend/experiment/rules/tests/test_hooked.py @@ -25,7 +25,7 @@ def test_hooked(self): participant=self.participant, playlist=playlist ) - rules = session.experiment_rules() + rules = session.block_rules() rules.plan_sections(session) plan = session.load_json_data().get('plan') assert plan is not None @@ -45,7 +45,7 @@ def test_eurovision(self): participant=self.participant, playlist=playlist ) - rules = session.experiment_rules() + rules = session.block_rules() for i in range(0, experiment.rounds): actions = rules.next_round(session) assert actions @@ -60,7 +60,7 @@ def test_thats_my_song(self): participant=self.participant, playlist=playlist ) - rules = session.experiment_rules() + rules = session.block_rules() assert rules.feedback_info() is None for i in range(0, experiment.rounds): @@ -125,12 +125,10 @@ def test_hooked_china(self): participant=self.participant, playlist=playlist ) - rules = session.experiment_rules() + rules = session.block_rules() assert rules.feedback_info() is not None question_trials = rules.get_questionnaire(session) # assert len(question_trials) == len(rules.questions) keys = [q.feedback_form.form[0].key for q in question_trials] questions = rules.question_series[0]['keys'][0:3] assert set(keys).difference(set(questions)) == set() - - diff --git a/backend/experiment/rules/tests/test_matching_pairs.py b/backend/experiment/rules/tests/test_matching_pairs.py index e02602e7f..f5576a476 100644 --- a/backend/experiment/rules/tests/test_matching_pairs.py +++ b/backend/experiment/rules/tests/test_matching_pairs.py @@ -40,11 +40,11 @@ def setUpTestData(cls): participant=cls.participant, playlist=cls.playlist ) - cls.rules = cls.session.experiment_rules() - + cls.rules = cls.session.block_rules() + def test_matching_pairs_trial(self): self.rules.num_pairs = 2 - for i in range(6): + for i in range(6): trial = self.rules.get_matching_pairs_trial(self.session) assert trial data = self.session.load_json_data() diff --git a/backend/experiment/rules/tests/test_matching_pairs_variants.py b/backend/experiment/rules/tests/test_matching_pairs_variants.py index 6b7fa7b96..e4091702d 100644 --- a/backend/experiment/rules/tests/test_matching_pairs_variants.py +++ b/backend/experiment/rules/tests/test_matching_pairs_variants.py @@ -36,13 +36,13 @@ def test_lite_version(self): participant=self.participant, playlist=self.playlist ) - first_trial = session.experiment_rules().get_matching_pairs_trial(session) + first_trial = session.block_rules().get_matching_pairs_trial(session) another_session = Session.objects.create( experiment=experiment, participant=self.participant, playlist=self.playlist ) - second_trial = another_session.experiment_rules( + second_trial = another_session.block_rules( ).get_matching_pairs_trial(another_session) assert isinstance(first_trial, Trial) assert isinstance(second_trial, Trial) @@ -56,13 +56,13 @@ def test_fixed_order_sections(self): participant=self.participant, playlist=self.playlist ) - first_trial = session.experiment_rules().get_matching_pairs_trial(session) + first_trial = session.block_rules().get_matching_pairs_trial(session) another_session = Session.objects.create( experiment=experiment, participant=self.participant, playlist=self.playlist ) - second_trial = another_session.experiment_rules( + second_trial = another_session.block_rules( ).get_matching_pairs_trial(another_session) assert isinstance(first_trial, Trial) assert isinstance(second_trial, Trial) diff --git a/backend/experiment/tests/test_forms.py b/backend/experiment/tests/test_forms.py index e76b5998e..babe045f6 100644 --- a/backend/experiment/tests/test_forms.py +++ b/backend/experiment/tests/test_forms.py @@ -1,6 +1,6 @@ from django.test import TestCase -from experiment.forms import ExperimentForm, ExportForm, TemplateForm, EXPERIMENT_RULES, SESSION_CHOICES, RESULT_CHOICES, EXPORT_OPTIONS, TEMPLATE_CHOICES +from experiment.forms import ExperimentForm, ExportForm, TemplateForm, BLOCK_RULES, SESSION_CHOICES, RESULT_CHOICES, EXPORT_OPTIONS, TEMPLATE_CHOICES class ExperimentFormTest(TestCase): @@ -16,7 +16,7 @@ def test_form_fields(self): def test_rules_field_choices(self): form = ExperimentForm() - expected_choices = [(i, EXPERIMENT_RULES[i].__name__) for i in EXPERIMENT_RULES] + expected_choices = [(i, BLOCK_RULES[i].__name__) for i in BLOCK_RULES] expected_choices.append(("", "---------")) self.assertEqual(form.fields['rules'].choices, sorted(expected_choices)) diff --git a/backend/experiment/views.py b/backend/experiment/views.py index 5c8ffcf33..983987b45 100644 --- a/backend/experiment/views.py +++ b/backend/experiment/views.py @@ -9,7 +9,7 @@ from .models import Block, ExperimentCollection, Phase, Feedback from section.models import Playlist from experiment.serializers import serialize_actions, serialize_experiment_collection, serialize_phase -from experiment.rules import EXPERIMENT_RULES +from experiment.rules import BLOCK_RULES from experiment.actions.utils import COLLECTION_KEY from image.serializers import serialize_image from participant.utils import get_participant @@ -177,7 +177,7 @@ def validate_experiment_playlist( if not playlists: return JsonResponse({'status': 'error', 'message': 'The experiment must have a playlist.'}) - rules = EXPERIMENT_RULES[rules_id]() + rules = BLOCK_RULES[rules_id]() if not rules.validate_playlist: return JsonResponse({'status': 'warn', 'message': 'This rulesset does not have a playlist validation.'}) diff --git a/backend/result/utils.py b/backend/result/utils.py index 2906024e8..8d47b2c60 100644 --- a/backend/result/utils.py +++ b/backend/result/utils.py @@ -63,7 +63,7 @@ def prepare_result(question_key: str, session: Session, **kwargs) -> int: - session: the session on which the Result is going to be registered possible kwargs: - section: optionally, provide a section to which the Result is going to be tied - - expected_response: optionally, provide the correct answer, used for scoring + - expected_response: optionally, provide the correct answer, used for scoring - json_data: optionally, provide json data tied to this result - comment: optionally, provide a comment to be saved in the database, e.g. "training phase" - scoring_rule: optionally, provide a scoring rule @@ -94,7 +94,7 @@ def score_result(data, session): # Calculate score: by default, apply a scoring rule # Can be overridden by defining calculate_score in the rules file if result.session: - score = session.experiment_rules().calculate_score(result, data) + score = session.block_rules().calculate_score(result, data) # refresh session data in case anything was changed within calculate_score function session.refresh_from_db() else: diff --git a/backend/result/views.py b/backend/result/views.py index 7626e447b..ffc80ee15 100644 --- a/backend/result/views.py +++ b/backend/result/views.py @@ -38,7 +38,7 @@ def score(request): def intermediate_score(request): session = verify_session(request) result = request.POST.get("json_data") - score = session.experiment_rules().calculate_intermediate_score(session, result) + score = session.block_rules().calculate_intermediate_score(session, result) return JsonResponse({'score': score}) diff --git a/backend/session/models.py b/backend/session/models.py index efb5b3034..5372d3c6e 100644 --- a/backend/session/models.py +++ b/backend/session/models.py @@ -209,7 +209,7 @@ def section_from_used_song(self): # Return a random section return self.section_from_song(song_id) - def experiment_rules(self): + def block_rules(self): """Get rules class to be used for this session""" return self.block.get_rules() diff --git a/backend/session/views.py b/backend/session/views.py index 9c1e0100e..1864b3dda 100644 --- a/backend/session/views.py +++ b/backend/session/views.py @@ -52,7 +52,7 @@ def continue_session(request, session_id): session = get_object_or_404(Session, pk=session_id) # Get next round for given session - action = serialize_actions(session.experiment_rules().next_round(session)) + action = serialize_actions(session.block_rules().next_round(session)) return JsonResponse(action, json_dumps_params={'indent': 4}) @@ -78,7 +78,7 @@ def next_round(request, session_id): session.save_json_data({COLLECTION_KEY: collection_slug}) # Get next round for given session - actions = serialize_actions(session.experiment_rules().next_round(session)) + actions = serialize_actions(session.block_rules().next_round(session)) if not isinstance(actions, list): if actions.get('redirect'):