Skip to content

Commit

Permalink
CI: Replace autopep8 & flake8 by ruff for linting backend code (#1201)
Browse files Browse the repository at this point in the history
* chore(deps): Replace autopep8 & flake8 by ruff

* refactor: Replace flake8 with ruff for linting backend code

* feat: Add script to format backend code

* config: Add the default `ruff.toml` configuration

* chore: Rename script to `format-back`

* config: Inherit `flake8` lint configuration in Ruff

* fix(lint): Fix linting error

* config: Allow parameters in the backend lint script

* docs: Recommend vscode ruff extension to use with this project

* fix: Apply suggestions from code review
  • Loading branch information
drikusroor authored Jul 25, 2024
1 parent cd1b049 commit c85dc8a
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 87 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ jobs:
- uses: actions/checkout@v3
- name: Lint Backend
continue-on-error: false
run: sudo docker-compose --env-file .env-github-actions run server bash -c "flake8"
run: sudo docker-compose --env-file .env-github-actions run server bash -c "ruff check"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.env
.vscode
.vscode/*
!.vscode/extensions.json
.DS_Store

node_modules/
Expand Down
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"charliermarsh.ruff"
]
}
121 changes: 56 additions & 65 deletions backend/experiment/rules/toontjehoger_5_tempo.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


class ToontjeHoger5Tempo(Base):
ID = 'TOONTJE_HOGER_5_TEMPO'
ID = "TOONTJE_HOGER_5_TEMPO"
TITLE = ""
SCORE_CORRECT = 20
SCORE_WRONG = 0
Expand All @@ -32,15 +32,15 @@ def first_round(self, block):
explainer = Explainer(
instruction="Timing en tempo",
steps=[
Step("Je krijgt dadelijk twee verschillende uitvoeringen van hetzelfde stuk te horen."),
Step(
"Je krijgt dadelijk twee verschillende uitvoeringen van hetzelfde stuk te horen."),
Step("Eén wordt op de originele snelheid (tempo) afgespeeld, terwijl de ander iets is versneld of vertraagd."),
Step(
"Kan jij horen welke het origineel is?"),
Step("Let hierbij vooral op de timing van de muzikanten.")
"Eén wordt op de originele snelheid (tempo) afgespeeld, terwijl de ander iets is versneld of vertraagd."
),
Step("Kan jij horen welke het origineel is?"),
Step("Let hierbij vooral op de timing van de muzikanten."),
],
step_numbers=True,
button_label="Start"
button_label="Start",
)

return [
Expand All @@ -66,32 +66,35 @@ def next_round(self, session):

def get_random_section_pair(self, session, genre):
"""
- session: current Session
- genre: (C)lassic (J)azz (R)ock
Voor de track: genereer drie random integers van 1-5 (bijv. [4 2 4])
Plak deze aan de letters C, J en R (bijv. [C4, J2, R4])
Voor het paar: genereer drie random integers van 1-2 (bijv. [1 2 2])
Plak deze aan de letter P (bijv. P1, P2, P2)
We willen zowel de originele als de veranderde versie van het paar. Dus combineer
bovenstaande met OR en CH (bijv. “C4_P1_OR”, “C4_P1_CH”, etc.)
- session: current Session
- genre: (C)lassic (J)azz (R)ock
Voor de track: genereer drie random integers van 1-5 (bijv. [4 2 4])
Plak deze aan de letters C, J en R (bijv. [C4, J2, R4])
Voor het paar: genereer drie random integers van 1-2 (bijv. [1 2 2])
Plak deze aan de letter P (bijv. P1, P2, P2)
We willen zowel de originele als de veranderde versie van het paar. Dus combineer
bovenstaande met OR en CH (bijv. “C4_P1_OR”, “C4_P1_CH”, etc.)
"""
# Previous tags
previous_tags = [
result.section.tag for result in session.result_set.all()]
previous_tags = [result.section.tag for result in session.result_set.all()]

# Get a random, unused track
# Loop until there is a valid tag
iterations = 0
valid_tag = False
tag_base = ""
tag_original = ""
while (not valid_tag):
while not valid_tag:
track = random.choice([1, 2, 3, 4, 5])
pair = random.choice([1, 2])
tag_base = "{}{}_P{}_".format(genre.upper(), track, pair, )
tag_base = "{}{}_P{}_".format(
genre.upper(),
track,
pair,
)
tag_original = tag_base + "OR"
if not (tag_original in previous_tags):
if tag_original not in previous_tags:
valid_tag = True

# Failsafe: prevent infinite loop
Expand All @@ -102,26 +105,21 @@ def get_random_section_pair(self, session, genre):

tag_changed = tag_base + "CH"

section_original = session.section_from_any_song(
filter_by={'tag': tag_original, 'group': "or"})
section_original = session.section_from_any_song(filter_by={"tag": tag_original, "group": "or"})

if not section_original:
raise Exception(
"Error: could not find original section: {}".format(tag_original))
raise Exception("Error: could not find original section: {}".format(tag_original))

section_changed = self.get_section_changed(
session=session, tag=tag_changed)
section_changed = self.get_section_changed(session=session, tag=tag_changed)

sections = [section_original, section_changed]
random.shuffle(sections)
return sections

def get_section_changed(self, session, tag):
section_changed = session.section_from_any_song(
filter_by={'tag': tag, 'group': "ch"})
section_changed = session.section_from_any_song(filter_by={"tag": tag, "group": "ch"})
if not section_changed:
raise Exception(
"Error: could not find changed section: {}".format(tag))
raise Exception("Error: could not find changed section: {}".format(tag))
return section_changed

def get_trial_question(self):
Expand All @@ -137,12 +135,12 @@ def get_round(self, session, round):
# Player
playback = Multiplayer(
sections,
labels=create_player_labels(len(sections), 'alphabetic'),
style=FrontendStyle(EFrontendStyle.NEUTRAL_INVERTED)
labels=create_player_labels(len(sections), "alphabetic"),
style=FrontendStyle(EFrontendStyle.NEUTRAL_INVERTED),
)

# Question
key = 'pitch'
key = "pitch"
question = ButtonArrayQuestion(
question=self.get_trial_question(),
key=key,
Expand All @@ -152,10 +150,12 @@ def get_round(self, session, round):
},
submits=True,
result_id=prepare_result(
key, session, section=section_original,
expected_response="A" if sections[0].id == section_original.id else "B"
key,
session,
section=section_original,
expected_response="A" if sections[0].id == section_original.id else "B",
),
style=STYLE_NEUTRAL_INVERTED
style=STYLE_NEUTRAL_INVERTED,
)
form = Form([question])

Expand All @@ -173,17 +173,13 @@ def get_section_pair_from_result(self, result):
section_original = result.section

if section_original is None:
raise Exception(
"Error: could not get section from result")
raise Exception("Error: could not get section from result")

tag_changed = section_original.tag.replace("OR", "CH")
section_changed = self.get_section_changed(
session=result.session, tag=tag_changed)
section_changed = self.get_section_changed(session=result.session, tag=tag_changed)

if section_changed is None:
raise Exception(
"Error: could not get changed section for tag: {}".format(
tag_changed))
raise Exception("Error: could not get changed section for tag: {}".format(tag_changed))

return (section_original, section_changed)

Expand All @@ -196,34 +192,34 @@ def get_score(self, session):
feedback = "Er is een fout opgetreden"
else:
if last_result.score == self.SCORE_CORRECT:
feedback = "Goedzo! Het was inderdaad antwoord {}!".format(
last_result.expected_response.upper())
feedback = "Goedzo! Het was inderdaad antwoord {}!".format(last_result.expected_response.upper())
else:
feedback = "Helaas! Het juiste antwoord was {}.".format(
last_result.expected_response.upper())
feedback = "Helaas! Het juiste antwoord was {}.".format(last_result.expected_response.upper())

section_original, section_changed = self.get_section_pair_from_result(
last_result)
section_original, section_changed = self.get_section_pair_from_result(last_result)

# Create feedback message
# - Track names are always the same
# - Artist could be different
if section_original.song.artist == section_changed.song.artist:
feedback += " Je hoorde {}, in beide fragmenten uitgevoerd door {}.".format(
last_result.section.song.name, last_result.section.song.artist)
last_result.section.song.name, last_result.section.song.artist
)
else:
section_a = section_original if last_result.expected_response == "A" else section_changed
section_b = section_changed if section_a.id == section_original.id else section_original
feedback += " Je hoorde {} uitgevoerd door A) {} en B) {}.".format(
section_a.song.name, non_breaking_spaces(section_a.song.artist), non_breaking_spaces(section_b.song.artist))
section_a.song.name,
non_breaking_spaces(section_a.song.artist),
non_breaking_spaces(section_b.song.artist),
)

# Return score view
config = {'show_total_score': True}
config = {"show_total_score": True}
score = Score(session, config=config, feedback=feedback)
return [score]

def get_final_round(self, session):

# Finish session.
session.finish()
session.save()
Expand All @@ -242,28 +238,26 @@ def get_final_round(self, session):
session=session,
final_text=final_text,
rank=toontjehoger_ranks(session),
button={'text': 'Wat hebben we getest?'}
button={"text": "Wat hebben we getest?"},
)

# Info page
body = render_to_string(
join('info', 'toontjehoger', 'experiment5.html'))
body = render_to_string(join("info", "toontjehoger", "experiment5.html"))
info = Info(
body=body,
heading="Timing en tempo",
button_label="Terug naar ToontjeHoger",
button_link=get_current_experiment_url(session)
button_link=get_current_experiment_url(session),
)

return [*score, final, info]

def validate_tags(self, tags):

errors = []
erroneous_tags = []

for tag in tags:
if not re.match(r'^[CJR][1-5]_P[12]_(OR|CH)$', tag):
if not re.match(r"^[CJR][1-5]_P[12]_(OR|CH)$", tag):
erroneous_tags.append(tag)

if erroneous_tags:
Expand All @@ -276,15 +270,12 @@ def validate_tags(self, tags):
return errors

def validate_playlist(self, playlist: Playlist):

errors = super().validate_playlist(playlist)
sections = playlist.section_set.all()
groups = sorted(list(set([section.group for section in sections])))

if groups != ['ch', 'or']:
errors.append(
"The playlist must contain two groups: 'or' and 'ch'. Found: {}".format(groups)
)
if groups != ["ch", "or"]:
errors.append("The playlist must contain two groups: 'or' and 'ch'. Found: {}".format(groups))

tags = sorted(list(set([section.tag for section in sections])))

Expand Down
7 changes: 2 additions & 5 deletions backend/requirements.in/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@ pylint
# Improve django code analysis
pylint-django

# Autoformatter
autopep8

# for simulating http requests in tests
requests

# Add pip-tools so we can use pip-compile in our develop environment
pip-tools

# Flake8 for linting
flake8
# Ruff for linting
ruff
16 changes: 3 additions & 13 deletions backend/requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ astroid==3.1.0
# via pylint
audioread==3.0.1
# via -r requirements.in/base.txt
autopep8==2.0.4
# via -r requirements.in/dev.txt
bleach==6.1.0
# via django-markup
build==1.0.3
Expand Down Expand Up @@ -53,8 +51,6 @@ docutils==0.20.1
# via
# django-markup
# python-creole
flake8==7.0.0
# via -r requirements.in/dev.txt
genbadge[coverage]==1.1.1
# via -r requirements.in/base.txt
html5lib==1.1
Expand All @@ -66,9 +62,7 @@ isort==5.13.2
markdown==3.5.2
# via django-markup
mccabe==0.7.0
# via
# flake8
# pylint
# via pylint
packaging==23.2
# via build
pillow==10.3.0
Expand All @@ -81,12 +75,6 @@ psycopg[binary]==3.1.18
# via -r requirements.in/base.txt
psycopg-binary==3.1.18
# via psycopg
pycodestyle==2.11.1
# via
# autopep8
# flake8
pyflakes==3.2.0
# via flake8
pygments==2.17.2
# via django-markup
pylint==3.1.0
Expand Down Expand Up @@ -114,6 +102,8 @@ requests==2.32.0
# genbadge
roman==4.1
# via -r requirements.in/base.txt
ruff==0.5.4
# via -r requirements.in/dev.txt
sentry-sdk==2.8.0
# via -r requirements.in/base.txt
six==1.16.0
Expand Down
Loading

0 comments on commit c85dc8a

Please sign in to comment.