Skip to content

Repository files navigation

study

Одна команда для учёбы в Moodle: сроки и баллы, материалы курсов, отправка ответов, релизы на GitVerse и SourceCraft, видео на Rutube — и готовая утренняя сводка, которую дочитывает ИИ-агент.

ci python deps platform license

Содержание

Возможности

  • Сроки и задания. Дедлайны со статусом ответа в ТУИС, просроченное, сдвинутые сроки, новые задания. Видит то, чего нет в обычном списке: элементы с ограничением доступа, выбор темы доклада — и выбрана ли она. Тесты — отдельной таблицей на месяц вперёд: попытки, лимит времени, начатые и не отправленные.
  • Баллы и уведомления. Итог по курсу (если Moodle его прячет — считается из работ), новые баллы и непрочитанные уведомления с прошлого запуска; автоматические отсеяны. Новые отзывы преподавателя — разделом «Отзывы», работа «на доработку» — в «Горит».
  • Объявления. Новые записи форумов объявлений курсов — по id, а не по дате: правки и посты задним числом тоже видны.
  • Материалы курсов. Появившиеся файлы поимённо и загрузка их в stash/ предмета.
  • Ответ на задание. Текст со ссылками на репозитории, релизы и скринкасты, вложения, отправка — только с --confirm: сохранение ответа в Moodle необратимо.
  • Релизы. Создание релиза по тегу и загрузка файлов на GitVerse и SourceCraft из каталога любого курса; ссылки в заметках подменяются под хостинг.
  • Rutube. Вход, свои видео и плейлисты, загрузка файла или импорт по URL.
  • Состояние работ. Что собрано, закоммичено, выпущено и отправлено — по git, собранным PDF и релизам.
  • Для агента. --json у любой команды — те же данные машиночитаемо; универсальная инструкция для ИИ-оператора ставится одной командой.

Как выглядит сводка

study state --pull печатает готовый markdown; разделы, в которых пусто, не выводятся. Пример с выдуманными курсами (databases, crypto — папки из config.env, у курса без папки в колонке стоит его название из Moodle):

# Учёба · чт 08.10 09:00

## Сроки

| Когда | Осталось | Работа | Курс | Состояние |
| ----- | -------- | ------ | ---- | --------- |
| **06.10 23:59** | **просрочено** | **ДЗ 2 — Нормализация до 3НФ** | **databases** | **не сдано** |
| 12.10 23:59 | 4 дн | ЛР 3 — Индексы и планы запросов | databases | не сдано |
| 15.10 23:59 | 7 дн | Тема доклада к лекции 5 | crypto | не выбрана, 9 вариантов |
| 15.10 23:59 | 7 дн | Доклад к лекции 5 | crypto | доступ закрыт |
| 20.10 23:55 | 12 дн | Расчётно-графическая работа | Теоретическая механика | не сдано |

## Тесты

| Когда | Осталось | Тест | Курс | Попытки | Время |
| ----- | -------- | ---- | ---- | ------- | ----- |
| **09.10 18:00** | **1 дн** | **Тест после лекции №4** | **crypto** | **0 из 2** | **15 мин** |
| 23.10 18:00 | 15 дн | Тест после лекции №5 | crypto | 0 из 2 | 15 мин |

## Баллы

| Курс | Итого | Новое |
| ---- | ----- | ----- |
| databases | 14.50 / 20 | ЛР 2 4.50/5 |
| crypto | 9.00 / 12 | — |

## Уведомления

| Когда | Тема |
| ----- | ---- |
| 07.10 16:42 | Оценена работа «ЛР 2. Хранимые процедуры» |

## Объявления

| Когда | Курс | Тема |
| ----- | ---- | ---- |
| 08.10 09:12 | databases | **Лекция 5 переносится** · Петров П.: на пятницу, аудитория та же. |

## Новое в курсах

| Курс | Раздел | Что | Файлы |
| ---- | ------ | --- | ----- |
| crypto | Лекции | Материалы лекции 5: новые файлы | 05-rsa.pdf, 05-rsa-slides.pdf |
| databases | Общее | Объявления: изменены настройки | — |

## Горит

- **ДЗ 2 — Нормализация до 3НФ** · databases · до 06.10 23:59 · просрочено · методички: databases/stash/
- **ЛР 3 — Индексы и планы запросов** · databases · до 12.10 23:59 · 4 дн · методички: databases/stash/

«Горит» — несданное, что просрочено или сдаётся в ближайшую неделю и что ТУИС ещё примет: работа с закрытым приёмом (у РУДН cutoff = срок) остаётся в «Сроках» как «приём закрыт», а в «Горит» идёт её «Пересдача …»; очное задание без ответа в ТУИС — тоже не «Горит». Это вывод программы, агент к нему ничего не дописывает.

Требования

  • Linux, macOS или Windows 10+ (в том числе WSL)
  • python3 3.8+, только стандартная библиотека
  • git
  • токены Moodle (служба Moodle mobile web service), GitVerse, SourceCraft — каждый нужен только для своего сервиса

Установка

Linux, macOS:

curl -fsSL https://raw.githubusercontent.com/nowherewashere/study-digest/master/install.py -o install.py && python3 install.py; rm -f install.py

Windows (PowerShell или Windows Terminal; у Python из Microsoft Store лаунчера py нет — тогда python install.py; в Git Bash — winpty py install.py, иначе вопросы не задаются):

iwr https://raw.githubusercontent.com/nowherewashere/study-digest/master/install.py -OutFile install.py; py install.py; del install.py

Установка скачивается и запускается, а не льётся в интерпретатор через пайп: она задаёт вопросы. install.py проверяет git и python3, клонирует репозиторий в <учебная директория>/.digest и передаёт дело study setup: токены, каталоги, проверка связи с Moodle, команда study в PATH, выбор ИИ-оператора, настройка курсов и первое наполнение stash/. Семь экранов, итог со всеми результатами; study setup можно запускать снова — перенастроить токены или курсы.

Команда study кладётся в ~/.local/bin: на Linux и macOS — симлинк (macOS: добавить export PATH="$HOME/.local/bin:$PATH" в ~/.zprofile), на Windows — study.cmd для cmd и PowerShell и sh-скрипт study для Git Bash; каталог добавляется в PATH пользователя с согласия, подействует в новом терминале. Все настройки и секреты — в .digest/config.env (на POSIX права 600; вне git, в репозитории только config.env.example). Токены Rutube инструмент ведёт сам в .digest/.secrets/.

Где взять токены
Сервис Где
Moodle профиль → «Ключи безопасности» → служба Moodle mobile web service; значение показывается один раз
GitVerse иконка пользователя → Настройки → Управление токенами, доступ «Репозитории»
SourceCraft Home → Access → Personal Access Tokens
Rutube jwt (аккаунты через VK ID / Gazprom ID): один раз скопировать refreshToken из cookie браузера (rutube.ru → DevTools → Application → Cookies) и сохранить study rt jwt — дальше годовой refresh сам выпускает короткий access. token (только аккаунты с паролем): study rt login. Режим задаёт --mode {auto,jwt,token}, auto предпочитает jwt

Быстрый старт

study me                    # токен Moodle работает?
study courses --setup       # какие курсы не отслеживать и как зовутся их папки
study agent claude          # инструкция для агента в CLAUDE.md (codex, gemini, copilot — см. ниже)
study files --pull          # материалы всех курсов в stash/ (study setup предлагает это сам)
study digest                # первый запуск сохраняет снимок состояния
study state --pull          # сводка + новые файлы курсов в stash/

Учебная директория вокруг .digest/ устроена просто: на каждый курс — папка с именем из строки CODE в config.env, внутри stash/ (материалы), tuis/ (ссылки на записи и заготовки ответов), NOTES.md (заметки по предмету; заготовку с шапкой и таблицами кладут study setup и study courses --setup, готовый файл не трогают) и репозиторий курса.

Ежедневная сводка

Основной режим: задача ИИ-оператора раз в день запускает study state --pull и печатает вывод как есть — сводка уже свёрстана программой, агент ничего не дописывает, файлов не читает и работу не начинает. Промпт задачи — docs/daily-digest-prompt.md.

Claude Code Desktop

Code → Routines → New routine → Local (облачной задаче недоступны локальные файлы и токены):

Поле Значение
Working folder корень учебной директории
Schedule Daily, 9:00
Instructions текст из docs/daily-digest-prompt.md после черты

После создания — Run now и «always allow» на запросах разрешений: разрешение выдаётся на study (в варианте с WSL — на wsl.exe) один раз, иначе следующие запуски встанут на подтверждении.

Linux и macOS

Ничего особенного: команда study в ~/.local/bin, задача запускает study state --pull из корня учебной директории. Если PATH задачи не содержит ~/.local/bin (macOS без строки в ~/.zprofile), промпт подсказывает запасной путь — python3 .digest/study state --pull.

Windows

Claude Code Desktop на Windows выполняет команды в Git Bash; он находит sh-скрипт ~/.local/bin/study, если %USERPROFILE%\.local\bin есть в PATH пользователя (это предлагает study setup), иначе — py .digest/study state --pull от рабочей папки. Вывод идёт в UTF-8 независимо от кодовой страницы консоли, файлы stash/ и NOTES.md читаются по обычным путям.

Windows + WSL

Вариант, когда программа живёт в WSL, а задача запускается в Windows. Рабочая папка задачи — \\wsl.localhost\<дистрибутив>\home\<…>\study, оболочка при этом windows-овая (Git Bash), и все команды идут через wsl.exe:

MSYS_NO_PATHCONV=1 wsl.exe -d <дистрибутив> -- bash -c '~/work/study/.digest/study state --pull'
Грабли
  • MSYS_NO_PATHCONV=1 обязателен: без него Git Bash подставляет windows-путь вместо unix-пути (/tmp/x.sh → C:/Program Files/Git/mnt/c/...), и команда не находится.
  • Однострочники bash -lc '…' переживают не всякие кавычки: в цикле for d in … переменная приходит пустой. Всё длиннее одной команды — в скрипт, записанный из Windows прямо в WSL (//wsl.localhost/<дистрибутив>/tmp/x.sh), запуск bash /tmp/x.sh.
  • Файлы (stash/, NOTES.md, config.env) читаются по windows-пути напрямую, но симлинки WSL через \\wsl.localhost не открываются — поэтому файл оператора это копия, а не ссылка.
  • Установка тоже из WSL: install.py там, где будет работать программа.

ИИ-оператор

Инструкция для агента — один текст, docs/AGENTS.md: что лежит в учебной директории, что умеет study, чего делать нельзя. У операторов различаются только имена файлов, которые они читают, поэтому study agent <код> кладёт этот текст блоком в нужный файл в корне учебной директории:

Код Кто читает Файл
claude Claude Code CLAUDE.md
codex OpenAI Codex; тот же файл читают Cursor, Copilot coding agent, Jules, Zed AGENTS.md
gemini Gemini CLI GEMINI.md
copilot GitHub Copilot в редакторе .github/copilot-instructions.md

Блок стоит между маркерами study:begin … study:end; всё вне его — личные правила (предметы, стиль коммитов, кто что делает), их команда не трогает. После обновления инструмента — study agent <код> ещё раз: блок перепишется, личное останется. Без аргумента команда показывает, какие файлы есть и актуален ли в них блок; операторов можно поставить несколько: study agent claude codex.

Команды

--help у любой команды. --json до или после имени команды печатает те же данные машиночитаемо — ровно то, что видит текстовый вывод, без второго обхода API. У state и digest в JSON есть schema — версия структуры: ломающее изменение увеличивает её, добавление полей — нет. Остальные команды отдают ответ API как есть.

Коды возврата: 0 — успех; 1 — план без подтверждения (submit без --confirm, rt upload без --confirm, update без --yes или с ответом «нет»); 2 — ошибка (текст и подсказка в stderr, а также неверные аргументы); 130 — прерывание.

Поля --json

study state: now, days, tuis (то же, что у digest, или null при --local), courses[] — курсы с папкой: id, code, title, flow (профиль сдачи), dir, repo (ветка, тег, незакоммиченное, remotes; у file — null), releases по хостингам, unreleased_tags, labs[] (готовность отчёта, презентации, видео, пара с заданием ТУИС); update — есть ли обновление инструмента; errors.

study digest (и tuis внутри state): first_run, since, courses, new_courses, deadlines (в окне), overdue (просрочено, не сдано), submitted (просрочено, сдано), not_started (несданное из обоих списков, кроме закрытых к приёму и очных — источник «Горит»), retakes (пересдачи с retake_of и needed), quizzes, updates (новое в курсах), new_assignments, moved (сдвинутые сроки), notifications, announcements (новое в форумах объявлений), feedback (новые отзывы преподавателя), grades, outside (сроки в скрытых курсах), errors. У каждого задания: assign_id, cmid, course, name, short, due (с учётом продления), submission (new · draft · reopened · submitted · offline · hidden), graded, grade, feedback, closed (приём закрыт), opens, canedit, locked, intro, lab, retake. Время везде — объект {ts, iso, text, full, left, left_sec, overdue}.

Сводка и работы

Команда Что делает
study state [--days N] [--local] [--no-save] [--pull] [--since X] готовая сводка; --local — без ТУИС, --pull — забрать новые файлы в stash/
study digest [--days N] [--no-save] [--since X] та же сводка, только по ТУИС
study task <код> <NN|id|cmid> карточка задания: текст, срок, что принимает, состояние и отзыв, что есть на диске; ничего не сохраняет
study answer <код> <NN> [--tag T] заготовка ответа по лабораторной — курсы с профилем release
study agent [код …] файл инструкций для ИИ-оператора: состояние / поставить
study setup первоначальная настройка: токены, каталоги, команда в PATH, оператор, курсы
study update [--check] обновить инструмент из репозитория и блоки агента; --check — только посмотреть
study --version версия: тег и число коммитов после него

ТУИС (Moodle)

Команда Что делает
study me владелец токена и число доступных функций
study courses [--all] [--setup] курсы: список / интерактивная настройка игнора и папок
study assigns [--course id|код] задания и сроки; в --json — ещё и intro, текст задания
study calendar [--days N] события календаря (только дедлайны)
study grades [--course id|код] баллы
study status <id-задания> состояние ответа на задание
study files [<курс>] [--pull] [--all] [--force] файлы курса: что появилось, забрать в stash/; перезалитый в ТУИС файл перекачивается поверх копии (mtime копии = timemodified из ТУИС); --force — всё заново; без курса — по всем папкам из config.env, строкой на курс
study upload <файл>… [--itemid N] загрузка вложений, печатает itemid
study submit <id> [--text F] [--attach <файл>…] [--files <itemid>] --confirm отправка ответа; без --confirm — план и код возврата 1. План показывает, что принимает задание (текст, число/типы/размер файлов), и отказывает при несовпадении даже с --confirm; --attach загружает файлы сам при отправке
study functions [подстрока] · study call <функция> [ключ=значение …] ручки Moodle и произвольный вызов; повтор ключа — массив: options[ids][0]=101

Хостинги кода

study gv releases | release <тег> --title T --notes F | update <тег> --notes F | asset <id-релиза> <файл> | api <путь>
study sc releases | release <тег> --title T --notes F | update <тег> --notes F | asset <тег> <файл>       | api <путь>

Репозиторий берётся из git-remote каталога, откуда запущена команда (origin — GitVerse, src — SourceCraft; remote на другой хостинг не считается), иначе из GV_REPO / SC_REPO. gv release подставляет SHA коммита по тегу: GitVerse не принимает имя ветки.

Rutube

study rt jwt [--refresh T] | login [--email E] | me | api <путь>
study rt categories | video <id> | edit <id> [--title T] [--desc F] [--category N] [--age A] [--hidden | --visible]
study rt playlist list | create --title T [--hidden] | add <id-плейлиста> <id-видео>
study rt upload <файл> | --url U [--title T] [--category N] [--age A] [--hidden] [--playlist ID] [--slot lab|report|presentation|defense] --confirm

Настройка

Всё изменяемое — в config.env.

Задача Что править
другой набор курсов в новом семестре study courses --setup (COURSE_IGNORE, строки CODE)
как сдаётся курс FLOW <id> release|file — спрашивает study courses --setup; без строки угадывается по репозиторию в папке
адрес Moodle, токены, окно дедлайнов TUIS_URL, TUIS_TOKEN и др., DIGEST_DAYS
вид сводки src/study/digest.py, функция render
шаги задачи агента docs/daily-digest-prompt.md
правила для агента docs/AGENTS.md, затем study agent <код>
новый источник данных src/study/moodle.py + src/study/digest.py + запись в docs/tuis-api.md
новый хостинг кода класс в src/study/hosting.py + запись в docs/hosting-api.md
новый ИИ-оператор строка в OPERATORS, src/study/agent.py

Курсы. Отслеживаются все курсы пользователя в ТУИС, кроме COURSE_IGNORE (id через пробел). Папку курса задаёт CODE <id> <имя папки>; курс без папки попадает в сводку по срокам, но локального состояния (git, релизы, лабы) у него нет. Профиль сдачи задаёт FLOW <id> release|file: release — репозиторий курса из шаблона преподавателя, git-flow, релиз с отчётом и презентацией на обоих хостингах, скринкасты, study answer, папка tuis/; file — отчёт файлом, работа в <код>/labNN/, сдача study submit --attach, репозиторий и хостинги не смотрятся. Без строки FLOW профиль угадывается: release, если в папке курса есть репозиторий, иначе file (study courses показывает его со знаком «?»). Курсы из COURSE_IGNORE в сводке не появляются нигде; сроки курса, скрытого в самом ТУИС (не в игноре), показываются разделом «Сроки в скрытых курсах» — вдруг скрыт по ошибке. Курс, которого не было в снимке (новая запись или снятый игнор), сводка объявляет строкой «Новый курс в ТУИС: … — строка CODE или COURSE_IGNORE в config.env». Это объявление бывает один раз, поэтому курс без папки сводка дальше называет строкой «Без папки (файлы не скачиваются): … (id N)» в каждом запуске, пока ему не задали CODE или не отправили в COURSE_IGNORE.

Снимок состояния. «Новое» в сводке — новое с прошлого запуска: .digest/.state.json (время запуска, сроки, баллы, список и состав курсов) обновляется каждым state/digest без --no-save, копия за день — в .digest/state/ГГГГ-ММ-ДД.json (60 дней). --since пересчитывает от другой точки: --since 2026-09-12 или --since 3 (дней назад) — ближайший снимок не позже даты, --since never — как при первом запуске, --since all — новым считается всё. С --no-save это взгляд назад, без него следующий снимок перепишется. Файлы пишутся через временный и os.replace, обрыв не оставит половины; если .state.json всё же повреждён (правка руками), берётся последний целый дневной снимок, а без него — как первый запуск, о чём сводка говорит в строке «Не удалось». Файлы курса сверяются с составом из снимка, а не только по дате: файл, скопированный преподавателем из прошлогоднего курса или открытый студентам, приходит со старой timemodified, и core_course_get_updates_since его не видит.

Сбои сети. Чтение из Moodle (все ручки, кроме отправки ответа), загрузка файлов и список релизов повторяются до трёх раз с паузой 2 с при обрыве, таймауте и HTTP 502–504; на 4xx, ошибку сертификата и ошибку в теле ответа Moodle повторов нет. Отправка ответа, релизы и загрузка видео идут одной попыткой. Раздел, который так и не удалось собрать, сводка пропускает и перечисляет в конце строкой «Не удалось: …» (в JSON — errors).

Обновление и версии

.digest/ — обычный git-клон, поэтому обновление — study update: git pull --ff-only и заново вписанный блок в файлах операторов (личное вне блока не трогается). Сводка study state сама проверяет origin (мягко: fetch до 20 с и одна повторная попытка, без запросов пароля; молчание GitHub — строка в «Не удалось», не сбой сводки) и, если есть новое, добавляет в конец строку «Обновление study: v1.0.0 → v1.1.0, 3 коммита — study update»; агент по своей инструкции предлагает обновиться, но не делает этого без согласия — код работает с токенами.

Перед pull команда показывает, что приедет: коммиты, diff --stat и результат git verify-commit верхнего коммита, — и в терминале спрашивает Обновить? [y/N]. Без терминала (задача агента, скрипт) нужен --yes, иначе печатается тот же план и код возврата 1. study update --check показывает план без изменений. Подпись проверяется ключом автора из связки gpg: без него строка «подпись НЕ проверена» — предупреждение, а не запрет; чтобы проверка что-то значила, импортируйте ключ из подписанных тегов репозитория.

Версии — теги vX.Y.Z на master и GitHub Releases с заметками по conventional commits; study --version печатает тег и число коммитов после него. master всегда рабочий — именно его ставит install.py.

Нашли ошибку. Issue или pull request в этот репозиторий — как обычно. Локально код лучше не править: study update делает git pull --ff-only, и локальный коммит его остановит, а незакоммиченная правка при следующем pull того же файла даст конфликт. Первый внешний PR (падение --since all на Windows) вошёл в v1.4.0 вместе с регрессионным тестом.

Рабочий процесс

Материалы. study files <код> показывает появившееся с прошлой сводки, --all — всё, --pull скачивает документы (.pdf, .docx, .md, .tex, архивы и подобные) до 50 МБ в <код>/stash/; в пустую stash/ забирает всё — так наполняют её в первый раз (study setup предлагает это сам). study files --pull без курса проходит по всем папкам из config.env. Страницы курса, видео и образы пропускаются; ссылки курса (mod_url: онлайн-лекции и т. п.) показываются строкой «ссылка … → URL» и попадают в «Новое в курсах»; файл, лежащий где угодно внутри stash/, повторно не качается.

Карточка задания. study task <код> <NN|id|cmid> печатает всё, что нужно, чтобы разобрать задание: текст целиком, срок, что принимает (число, типы и размер файлов, текст), состояние ответа, балл и отзыв преподавателя, что уже есть на диске (у release — лаба репозитория с готовностью отчёта, презентации и видео; у file — <код>/labNN/ и собранные PDF), файлы stash/ с этим номером в имени. Ничего не сохраняет: источник — ТУИС.

Два источника заданий. mod_assign_get_assignments знает всё про приём ответа, но молчит о заданиях с ограничением доступа; core_course_get_contents отдаёт их, но знает только имя, срок, описание и причину недоступности. Слияние делает реестр (study/assigns.py), и на нём стоят сводка, study task, study assigns и предполёт study submit — поэтому одно и то же задание везде видно одинаково. У задания, пришедшего только из состава курса, нет assign_id: карточка покажет срок и причину («нужна группа …»), а отправка откажет — слать некуда.

Ответ на лабораторную (профиль release). study answer <код> <NN> собирает текст ответа: репозитории — из git-remote, тег — последний или --tag, PDF отчёта и презентации — из _output/. Ссылок на скринкасты в API нет, они хранятся в <код>/tuis/labNN.env (четыре записи на двух площадках плюс два плейлиста); первый запуск создаёт файл пустым, второй пишет <код>/tuis/labNN.md. Затем study submit <id> --text <код>/tuis/labNN.md --attach <отчёт.pdf> <презентация.pdf>: план сверяет текст и файлы с настройками задания, с --confirm загружает файлы и отправляет (старый путь study upload → --files <itemid> остаётся). Оба файла лежат вне репозитория курса. Полный чек-лист от выполнения до ответа — docs/lab-submission.md.

Документация и устройство

Файл Для кого
docs/AGENTS.md ИИ-агент: что здесь лежит, команды, правила, грабли — ставится study agent
docs/daily-digest-prompt.md задача ежедневной сводки
docs/lab-submission.md чек-лист сдачи работы с релизом и скринкастами
docs/tuis-api.md ручки Moodle и их особенности
docs/hosting-api.md API GitVerse и SourceCraft
.digest/
├── study                 запускающий файл (лаунчер); на Windows включает UTF-8 и VT-режим
├── src/study/            пакет: cli · digest (сводка) · moodle · hosting · rutube · files
│                         · answer · courses · agent · setup · config · net · fmt · local · snapshot
├── docs/                 документация
├── tests/                unittest, только stdlib; сеть подменена, ответы ТУИС — в fixtures/
├── install.py            установка: зависимости, клон, затем study setup
├── setup.sh              обёртка над install.py ради старой ссылки
├── config.env.example    шаблон настроек
├── pyproject.toml        настройки проверки кода (ruff); пакет через pip не ставится
└── config.env · .secrets/ · .state.json · state/   личное, вне git

Все внешние вызовы идут через src/study/net.py (urllib), особенности каждого API спрятаны в его клиенте; cli.py только разбирает аргументы и печатает.

Разработка

python3 -m unittest -v                       # тесты, без сети и токенов (см. ниже)
uvx ruff check src tests study install.py    # стиль и ошибки, правила в pyproject.toml
shellcheck setup.sh

Тесты не ходят в сеть: tests/__init__.py подменяет urllib.request.urlopen заглушкой, которая падает на любом вызове, а тесты сетевых модулей ставят поверх net.send tests/fakes.py: FakeNet — очередь ответов по (метод, подстроки: в «МЕТОД url» или целиком поле формы k=v) и запись всего отправленного (form, json_body, files, заголовки, сырое тело). Ответы Moodle — tests/fixtures/*.json по форме из docs/tuis-api.md, эталон сводки — fixtures/digest.md; время в них отсчитано от fakes.NOW (16.09.2026 09:00 MSK), тесты сводки фиксируют time.time и TZ. Git подменяется картой ответов (hosting) или временными репозиториями (answer, state, update, install); токены — тестовые строки во временном config.env, переменные окружения study и глобальный gitconfig на тесты не влияют. study setup и install.py проходятся с подменёнными input/getpass. Кодировка у каждого read_text/write_text/open указана явно — за этим следит tests/test_style.py. Тесты, которые качают файлы, подменяют ROOT временным каталогом — иначе запись уйдёт в настоящий <код>/stash/. Синтаксис — Python 3.8: без match, X | Y в аннотациях, removeprefix.

То же самое гоняет CI на ubuntu, macos и windows с Python 3.8 и 3.12 при каждом push (TZ=MSK-3: на Windows нет tzset, пояс задаётся окружением). Коммиты — conventional (feat, fix, docs, refactor, style, test, ci), версии — теги vX.Y.Z и Releases.

Лицензия

MIT.

About

CLI для учёбы в Moodle: сроки и баллы, материалы курсов, ответы на задания, релизы на GitVerse и SourceCraft, Rutube — и утренняя сводка для ИИ-агента (Claude Code, Codex, Gemini). Python, только stdlib

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages