Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 15 additions & 24 deletions app/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,20 +286,17 @@ def lesson(
),
text(
"if-result",
"Что выведет `if 3 > 5: print('да') else: print('нет')`?",
"Что выведет этот код?\n\nif 3 > 5:\n print('да')\nelse:\n print('нет')",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the line breaks in the if-result prompt

When this question is shown in lessons, exams, or practice, questionTemplate() inserts rich(question.prompt) into a normal <div>, and .question-prompt does not preserve whitespace. The browser therefore collapses these newlines and indentation, displaying the code approximately as if 3 > 5: print('да') else: print('нет')—the same invalid one-line syntax this change intends to fix. Render the snippet as a code block or otherwise preserve its whitespace.

Useful? React with 👍 / 👎.

["нет"],
"3 не больше 5, поэтому выполняется ветка else.",
),
code(
"if-code",
"Напиши `is_adult(age)`, возвращающую True при возрасте 18 и больше.",
"def is_adult(age):\n # твой код\n pass\n",
[
{"kind": "call", "call": "is_adult(18)", "expected": True},
{"kind": "call", "call": "is_adult(17)", "expected": False},
],
"Условие внутри функции помогает вернуть нужный логический результат.",
"Сравни age с 18 и верни результат сравнения либо используй if/else.",
"Дано `temperature = 22`. Если температура >= 25, выведи `Надень шорты`, иначе — `Возьми куртку`.",
"temperature = 22\n# твой код\n",
[{"kind": "stdout", "expected": "Возьми куртку"}],
"Условие выбирает одежду по температуре.",
"Проверь temperature >= 25: в одной ветке выведи про шорты, в другой — про куртку.",
),
],
),
Expand Down Expand Up @@ -339,14 +336,11 @@ def lesson(
text("for-sum", "Чему равна сумма чисел в `range(1, 4)`?", ["6"], "Это 1 + 2 + 3 = 6."),
code(
"for-code",
"Напиши `sum_to(number)`, возвращающую сумму от 1 до number включительно.",
"def sum_to(number):\n # твой код\n pass\n",
[
{"kind": "call", "call": "sum_to(1)", "expected": 1},
{"kind": "call", "call": "sum_to(5)", "expected": 15},
],
"Цикл избавляет от ручного сложения каждого числа.",
"Создай total = 0 и пройди range(1, number + 1).",
"Выведи числа от 1 до 5, каждое с новой строки.",
"# Напиши цикл\n",
[{"kind": "stdout", "expected": "1\n2\n3\n4\n5"}],
"Цикл for и range позволяют вывести числа без повторения print().",
"Пройди по range(1, 6) и выведи каждое число через print().",
),
],
),
Expand Down Expand Up @@ -392,14 +386,11 @@ def lesson(
),
code(
"while-code",
"Напиши `countdown(start)`, возвращающую список от start до 1 через while.",
"def countdown(start):\n # твой код\n pass\n",
[
{"kind": "call", "call": "countdown(1)", "expected": [1]},
{"kind": "call", "call": "countdown(4)", "expected": [4, 3, 2, 1]},
],
"Дано `start = 5`. Выведи обратный отсчёт до 1, каждое число с новой строки, затем `Пуск!`.",
"start = 5\n# твой код\n",
[{"kind": "stdout", "expected": "5\n4\n3\n2\n1\nПуск!"}],
"while хорош, когда счётчик меняется до достижения границы.",
"Начни с result = [] и уменьшай start после добавления в список.",
"Пока start больше 0, выводи его и уменьшай на 1. После цикла выведи «Пуск!».",
),
],
),
Expand Down
2 changes: 2 additions & 0 deletions app/static/styles.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions tests/test_curriculum.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import re
from pathlib import Path

from app.content import EXAMS, LESSONS, MODULES, QUESTION_BY_ID
from app.evaluator import evaluate
from app.extended_curriculum import EXTRA_LESSONS
Expand Down Expand Up @@ -78,3 +81,32 @@ def test_reference_solutions_for_lessons_13_25_pass_the_runner() -> None:
code_question = lesson["questions"][2]
result = evaluate(code_question, code_question["reference"])
assert result["correct"] is True, (lesson["order"], result)


def test_lessons_four_to_six_do_not_require_future_topics() -> None:
if_result = QUESTION_BY_ID["if-result"]
assert "\n" in if_result["prompt"]
assert (
if_result["prompt"]
== "Что выведет этот код?\n\nif 3 > 5:\n print('да')\nelse:\n print('нет')"
)

starters = {
"if-code": "temperature = 22\n# твой код\n",
"for-code": "# Напиши цикл\n",
"while-code": "start = 5\n# твой код\n",
}
for question_id, starter in starters.items():
question = QUESTION_BY_ID[question_id]
assert "def " not in question["prompt"]
assert "def " not in question["starter"]
assert question["starter"] == starter

styles = Path("app/static/styles.css").read_text(encoding="utf-8")
assert re.search(r"\.question-prompt\s*\{[^}]*white-space:\s*pre-wrap", styles)

assert QUESTION_BY_ID["if-code"]["tests"] == [{"kind": "stdout", "expected": "Возьми куртку"}]
assert QUESTION_BY_ID["for-code"]["tests"] == [{"kind": "stdout", "expected": "1\n2\n3\n4\n5"}]
assert QUESTION_BY_ID["while-code"]["tests"] == [
{"kind": "stdout", "expected": "5\n4\n3\n2\n1\nПуск!"}
]
Loading