Группы: ТОП-имена и порядок как в таблице
В таблице появились группы с «ТОП» в имени (ИВТ-ТОП-11БО, ИТ-ТОП-12БО): шаблон требовал цифру сразу после первого дефиса, поэтому такие столбцы пропускались целиком. Теперь имя группы — буквенные части через дефис, номер потока и необязательный суффикс, т.е. распознаются и «ИВТ-11БО», и «ПИЭ-13МО», и «ИВТ-ТОП-11БО» (похожие заголовки с пробелами — нет). GET /groups больше не сортирует по алфавиту с приоритетом БО/МО, а отдаёт группы в порядке столбцов таблицы — как просили, «как в расписании». Состав групп (появление/переименование/скрытие) подхватывается сам при следующем обновлении, потому что источник истины — заголовок листа. Тесты: ТОП-имена + порядок столбцов, отсев похожих не-групповых заголовков.
This commit is contained in:
@@ -32,7 +32,9 @@ nginx (https://schedule.our-place.ru) → 127.0.0.1:8090
|
||||
столбцы 2–3 даты «знаменателя»
|
||||
столбец 4 день недели (указан один раз на блок дня)
|
||||
столбец 5 номер пары и время (ячейка объединена на две строки пары)
|
||||
столбцы 6+ группы — по одному столбцу на группу (скрытые столбцы пропускаются)
|
||||
столбцы 6+ группы — по одному столбцу на группу, порядок столбцов = порядок
|
||||
групп на сайте (скрытые столбцы пропускаются; имена вида
|
||||
«ИВТ-11БО», «ПИЭ-13МО», «ИВТ-ТОП-11БО»)
|
||||
```
|
||||
|
||||
Каждый день занимает блок строк, и строки идут парами: «числитель» /
|
||||
@@ -168,7 +170,7 @@ tests/
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|---|---|---|
|
||||
| GET | `/groups` | список групп (сначала БО, потом МО) |
|
||||
| GET | `/groups` | группы в том порядке, в каком идут столбцы в таблице |
|
||||
| GET | `/schedule/{group}` | расписание группы с разбором на занятия |
|
||||
| GET | `/schedule/{group}/{day}` | расписание группы на конкретный день |
|
||||
| GET | `/today?group={group}` | расписание группы на сегодня |
|
||||
|
||||
@@ -165,11 +165,9 @@ def create_app(
|
||||
|
||||
@app.get("/groups")
|
||||
def groups() -> list[str]:
|
||||
"""Группы в том порядке, в каком идут столбцы в таблице."""
|
||||
data, _ = _data()
|
||||
return sorted(
|
||||
data.keys(),
|
||||
key=lambda g: (0 if g.endswith("БО") else (1 if g.endswith("МО") else 2), g),
|
||||
)
|
||||
return list(data.keys())
|
||||
|
||||
@app.get("/teachers")
|
||||
def teachers() -> list[str]:
|
||||
|
||||
@@ -35,7 +35,9 @@ _COL_DAY = 4 # день недели
|
||||
_COL_PERIOD = 5 # пара и время
|
||||
_FIRST_GROUP_COL = 6
|
||||
|
||||
_GROUP_RE = re.compile(r"^[А-ЯЁ]{2,4}-\d")
|
||||
# Имя группы: буквенные части через дефис, номер потока и необязательный
|
||||
# суффикс: «ИВТ-11БО», «ПИЭ-13МО», «ИВТ-ТОП-11БО», «ИТ-ТОП-12БО».
|
||||
_GROUP_RE = re.compile(r"^[А-ЯЁ]+(?:-[А-ЯЁ]+)*-\d{1,2}[А-ЯЁ]{0,3}$")
|
||||
_PERIOD_RE = re.compile(r"^\s*(\d{1,2})\s*(.*)$")
|
||||
_ROOM_RE = re.compile(r"ауд\.\s*([\w\-]+)", re.I)
|
||||
_SEMESTER_DATE_RE = re.compile(r"(\d{1,2}\.\d{1,2}\.\d{2})")
|
||||
@@ -108,13 +110,16 @@ def current_parity(week_ranges: list[dict], today: date | None = None) -> str |
|
||||
|
||||
|
||||
def _find_group_columns(header: list[str], hidden_cols: set[int]) -> dict[int, str]:
|
||||
"""Столбцы групп: имя из заголовка, порядок — как столбцы в таблице."""
|
||||
columns: dict[int, str] = {}
|
||||
seen: set[str] = set()
|
||||
for idx, cell in enumerate(header):
|
||||
if idx in hidden_cols:
|
||||
continue
|
||||
name = _normalize_header(cell)
|
||||
if name and _GROUP_RE.match(name) and name not in seen:
|
||||
if not name or name in seen or len(name) > 24:
|
||||
continue
|
||||
if _GROUP_RE.match(name):
|
||||
columns[idx] = name
|
||||
seen.add(name)
|
||||
return columns
|
||||
|
||||
@@ -46,6 +46,21 @@ def test_groups(client):
|
||||
assert client.get("/groups").json() == ["ИВТ-11БО", "ИТ-12БО"]
|
||||
|
||||
|
||||
def test_groups_keep_sheet_order(monkeypatch):
|
||||
"""GET /groups отдаёт группы в порядке столбцов таблицы, а не по алфавиту."""
|
||||
from fixtures import fixture_sheets
|
||||
from xlsx_builder import build_workbook
|
||||
|
||||
sheets = fixture_sheets()
|
||||
header = sheets["Бакалавры и магистры"].rows[0]
|
||||
header[6] = "ЯЯ-ТОП-11БО\nсеместр до 11.01.27"
|
||||
header[7] = "АА-11БО\nсеместр до 29.12.26"
|
||||
|
||||
cache, _, _ = make_cache(monkeypatch, build_workbook(sheets))
|
||||
with TestClient(main.create_app(cache)) as client:
|
||||
assert client.get("/groups").json() == ["ЯЯ-ТОП-11БО", "АА-11БО"]
|
||||
|
||||
|
||||
def test_teachers(client):
|
||||
assert client.get("/teachers").json() == [
|
||||
"Иванов И.И.", "Петров П.П.", "Сидорова С.С.", "Смирнов А.В.",
|
||||
|
||||
@@ -23,6 +23,28 @@ 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"
|
||||
|
||||
Reference in New Issue
Block a user