Files
schedule/tests/test_parsing.py
Vladislav Kopnin 475eb3801e Группы: ТОП-имена и порядок как в таблице
В таблице появились группы с «ТОП» в имени (ИВТ-ТОП-11БО, ИТ-ТОП-12БО):
шаблон требовал цифру сразу после первого дефиса, поэтому такие столбцы
пропускались целиком. Теперь имя группы — буквенные части через дефис,
номер потока и необязательный суффикс, т.е. распознаются и «ИВТ-11БО»,
и «ПИЭ-13МО», и «ИВТ-ТОП-11БО» (похожие заголовки с пробелами — нет).

GET /groups больше не сортирует по алфавиту с приоритетом БО/МО, а отдаёт
группы в порядке столбцов таблицы — как просили, «как в расписании».
Состав групп (появление/переименование/скрытие) подхватывается сам при
следующем обновлении, потому что источник истины — заголовок листа.

Тесты: ТОП-имена + порядок столбцов, отсев похожих не-групповых заголовков.
2026-09-30 09:42:27 +03:00

196 lines
7.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Тесты разбора листов: группы, дни/пары/чётность, индексы, вспомогательные листы."""
from datetime import date
import pytest
from fixtures import fixture_sheets, make_sheets
from schedule import parsing
from schedule.errors import ScheduleError
@pytest.fixture()
def sheets():
return make_sheets(fixture_sheets())
@pytest.fixture()
def data(sheets):
return parsing.parse_schedule(sheets)
def test_hidden_group_excluded(data):
assert set(data) == {"ИВТ-11БО", "ИТ-12БО"}
def test_group_names_with_top_and_sheet_order():
"""ТОП-группы распознаются, а порядок групп — как столбцы в таблице."""
sheets = fixture_sheets()
header = sheets[parsing.MAIN_SHEET].rows[0]
header[6] = "ИТ-ТОП-11БО\nсеместр до 11.01.27"
header[7] = "АА-11БО\nсеместр до 29.12.26"
data = parsing.parse_schedule(make_sheets(sheets))
assert list(data) == ["ИТ-ТОП-11БО", "АА-11БО"] # не по алфавиту, а по столбцам
assert data["ИТ-ТОП-11БО"]["days"]["понедельник"][1]["ч"]
def test_not_a_group_headers_ignored():
"""Похожие, но не групповые заголовки столбцами групп не становятся."""
sheets = fixture_sheets()
header = sheets[parsing.MAIN_SHEET].rows[0]
header[9] = "ИВТ 11БО" # пробел вместо дефиса — это не имя группы
data = parsing.parse_schedule(make_sheets(sheets))
assert set(data) == {"ИВТ-11БО", "ИТ-12БО"}
def test_semester(data):
assert data["ИВТ-11БО"]["semester_until"] == "11.01.27"
assert data["ИТ-12БО"]["semester_until"] == "29.12.26"
def test_day_period_parity(data):
mon = data["ИВТ-11БО"]["days"]["понедельник"]
p1 = mon[1]
assert p1["time"] == "9:00-10:35"
assert p1["ч"] is not None and p1["з"] is not None
assert "Математика" in p1["ч"]
assert "216" in p1["з"]
def test_empty_parity_slot_kept(data):
mon = data["ИТ-12БО"]["days"]["понедельник"]
assert mon[1]["з"] is None
# время на пустой слот подставлено
assert mon[1]["time"] == "9:00-10:35"
def test_lessons_preparsed(data):
mon = data["ИВТ-11БО"]["days"]["понедельник"]
lesson = mon[1]["lessons"]["ч"][0]
assert lesson["subject"] == "Математика"
assert lesson["teacher"] == "Смирнов А.В."
assert lesson["room"] == "ауд. 215"
assert lesson["note"] == "пара 14.09 не будет"
# пустое parity -> None
assert data["ИТ-12БО"]["days"]["понедельник"][1]["lessons"]["з"] is None
def test_marker_parsed(data):
mon_g1 = data["ИВТ-11БО"]["days"]["понедельник"]
mon_g2 = data["ИТ-12БО"]["days"]["понедельник"]
assert mon_g1[2]["lessons"]["ч"][0]["marker"] == "к.в. - 2"
assert mon_g2[2]["lessons"]["з"][0]["marker"] == "к.в."
def test_tuesday_only_ch(data):
tue = data["ИВТ-11БО"]["days"]["вторник"]
assert tue[1]["ч"] and "Биология" in tue[1]["ч"]
assert tue[1]["з"] is None
def test_missing_main_sheet(sheets):
del sheets[parsing.MAIN_SHEET]
with pytest.raises(ScheduleError):
parsing.parse_schedule(sheets)
def test_odd_day_block_warns(caplog):
sheets = make_sheets(fixture_sheets())
# уберём вторую строку понедельника (пара 1, з) -> нечётное число строк
rows = sheets[parsing.MAIN_SHEET].rows
# строки: 0 header, 1 с/по, 2..5 понедельник, 6..7 вторник
del rows[3]
with caplog.at_level("WARNING"):
result = parsing.parse_schedule(sheets)
assert any("сдвинуться" in r.message for r in caplog.records)
# разбор всё равно завершается
assert "ИВТ-11БО" in result
def test_week_ranges(sheets):
weeks = parsing.extract_week_ranges(sheets)
assert len(weeks) == 8
assert weeks[0] == {"parity": "ч", "start": date(2026, 8, 31), "end": date(2026, 9, 6)}
assert weeks[1]["parity"] == "з"
assert weeks[-2]["parity"] == "ч"
def test_current_parity():
sheets = make_sheets(fixture_sheets())
weeks = parsing.extract_week_ranges(sheets)
assert parsing.current_parity(weeks, date(2026, 9, 1)) == "ч"
assert parsing.current_parity(weeks, date(2026, 9, 9)) == "з"
assert parsing.current_parity(weeks, date(2030, 1, 1)) is None
def test_teacher_room_index(data):
teachers, rooms = parsing.build_teacher_room_index(data)
assert set(teachers) == {"Смирнов А.В.", "Иванов И.И.", "Петров П.П.", "Сидорова С.С."}
smirnov = teachers["Смирнов А.В."]["понедельник"]["1"]
assert len(smirnov["ч"]) == 1 and len(smirnov["з"]) == 1
assert smirnov["ч"][0]["subject"] == "Математика"
assert smirnov["ч"][0]["room"] == "ауд. 215"
assert smirnov["ч"][0]["groups"] == ["ИВТ-11БО"]
petrov_zn = teachers["Петров П.П."]["понедельник"]["2"]["з"]
assert petrov_zn[0]["marker"] == "к.в."
assert set(rooms) == {"ауд. 215", "ауд. 216", "ауд. 301", "ауд. 220", "ауд. 201"}
room_301 = rooms["ауд. 301"]["понедельник"]
assert room_301["1"]["ч"][0]["subject"] == "Физика"
assert room_301["1"]["ч"][0]["teacher"] == "Иванов И.И."
assert room_301["2"]["ч"][0]["groups"] == ["ИВТ-11БО"]
def test_day_times(data):
times = parsing.build_day_times(data)
assert times["понедельник"] == {"1": "9:00-10:35", "2": "10:45-12:20"}
assert times["вторник"] == {"1": "9:00-10:35"}
def test_group_schedule_shape(data):
out = parsing.build_group_schedule(data, "ИВТ-11БО")
assert out["group"] == "ИВТ-11БО"
assert out["semester_until"] == "11.01.27"
p1 = out["days"]["понедельник"]["1"]
assert p1["time"] == "9:00-10:35"
assert "raw" in p1["ч"] and "lessons" in p1["ч"]
assert p1["з"]["lessons"][0]["room"] == "ауд. 216"
assert parsing.build_group_schedule(data, "НЕТ-11БО") is None
def test_rooms_info(sheets):
info = parsing.parse_rooms_info(sheets)
assert info == {
"ауд. 215": {"room": "ауд. 215", "info": "комп.класс, 12 мест"},
"ауд. 301": {"room": "ауд. 301", "info": "интерактивная панель, 24 места"},
"ауд. 220": {"room": "ауд. 220", "info": "20 мест"},
}
def test_teachers_full(sheets):
full = parsing.parse_teachers_full(sheets)
assert full == {
"Смирнов А.В.": "Смирнов Александр Викторович",
"Иванов И.И.": "Иванов Иван Иванович",
}
def test_sort_rooms():
assert parsing.sort_rooms(["ауд. 10", "ауд. 9", "ауд. 100", "зал"]) == [
"ауд. 9", "ауд. 10", "ауд. 100", "зал",
]
def test_build_room_schedule(data):
_, rooms = parsing.build_teacher_room_index(data)
times = parsing.build_day_times(data)
out = parsing.build_room_schedule(rooms, "ауд. 301", times)
# дни с расписанием плюс дни, где есть время пар (даже без занятий)
assert set(out["days"]) == {"понедельник", "вторник"}
assert out["days"]["понедельник"]["1"]["ч"][0]["subject"] == "Физика"
assert parsing.build_room_schedule(rooms, "ауд. 999", times) is None