Skip to main content

pymirea

PyPI CI License: MIT Python 3.11+

Асинхронный Python-клиент для Пульса МИРЭА.

Поддерживает: вход с 2FA через Keycloak SSO, расписание занятий, оценки, посещаемость (отметка + детали), события турникетов (ACS), регистрацию в e-sports, шифрование сессий (Fernet + HKDF).

Установка

pip install pymirea

Первый запрос за 30 секунд

import asyncio
from pymirea import Config, configure, MireaAuth

# Сгенерируйте свой ключ один раз и сохраните:
#   python -c "import secrets,base64; print(base64.b64encode(secrets.token_bytes(32)).decode())"
configure(Config(session_keys="ВАША_BASE64_СТРОКА_32_БАЙТА"))

async def main():
    auth = MireaAuth()
    result = await auth.login("ваш_логин@edu.mirea.ru", "пароль")

    if result.challenge:
        # МИРЭА просит OTP (приходит на университетскую почту)
        code = input("Код из email: ")
        result = await auth.complete_2fa(result.challenge, code)

    print("Вошли! Токены:", result.tokens)

asyncio.run(main())

Примеры использования

1. Простой скрипт — получить расписание

import asyncio
from datetime import datetime
from pymirea import Config, configure, MireaAuth
from pymirea.grades import MireaGrades

configure(Config(session_keys="..."))

async def main():
    auth = MireaAuth()
    result = await auth.login("login@edu.mirea.ru", "пароль")
    # ... обработка 2FA если потребуется ...

    api = MireaGrades(session_cookies=result.tokens)
    schedule = await api.get_schedule(days=7)
    for lesson in schedule.lessons:
        when = datetime.fromtimestamp(lesson.start_epoch).strftime("%d.%m %H:%M")
        print(f"{when}  {lesson.name} — {lesson.teacher or '?'} ({lesson.room or '?'})")

asyncio.run(main())

Полная версия: examples/cli_schedule.py.

2. Telegram-бот на aiogram

from datetime import datetime
from aiogram import Bot, Dispatcher, types
from pymirea import Config, configure, MireaAuth
from pymirea.grades import MireaGrades

configure(Config(session_keys="..."))

bot = Bot(token="...")
dp = Dispatcher()

# user_id -> session cookies (в продакшене — в БД, зашифрованно через SessionCrypto)
sessions: dict[int, dict] = {}

@dp.message(commands=["schedule"])
async def cmd_schedule(msg: types.Message):
    cookies = sessions.get(msg.from_user.id)
    if not cookies:
        await msg.answer("Сначала /login")
        return
    api = MireaGrades(session_cookies=cookies)
    sched = await api.get_schedule(days=3)
    lines = [
        f"{datetime.fromtimestamp(l.start_epoch).strftime('%d.%m %H:%M')} — {l.name}"
        for l in sched.lessons
    ]
    await msg.answer("\n".join(lines) or "Пар не найдено")

Полная версия: examples/telegram_bot.py.

3. Отметить посещаемость себе и друзьям одним QR-сканом

Классический MireaScanner-флоу — сделайте своё приложение за 20 минут:

from pymirea import MireaAPI, SessionCrypto
from pymirea.crypto import get_crypto

crypto = get_crypto()

# Загрузите из своей БД зашифрованные сессии друзей
friends = [
    (123, "Эллиот", crypto.decrypt_session(row_elliot)),
    (456, "Уолтер", crypto.decrypt_session(row_walter)),
]

api = MireaAPI(session_cookies=my_session)
results = await api.mark_attendance_for_group(qr_data, friends)

for r in results:
    print(f"{r.user_name}: {'✓' if r.success else '✗ ' + r.message}")

mark_attendance_for_group сам извлекает токен из QR-URL, проходит по всем переданным сессиям и возвращает список AttendanceResult — готово к отображению в UI.

4. FastAPI-веб-сервис

from fastapi import FastAPI, Depends, HTTPException
from pymirea import Config, configure
from pymirea.grades import MireaGrades
from pymirea.crypto import get_crypto

configure(Config(session_keys="..."))
crypto = get_crypto()
app = FastAPI()

def current_session(token: str = Depends(...)) -> dict:
    """Расшифровать сессию пользователя из вашего хранилища."""
    encrypted = your_db.get_mirea_session(user_id_from(token))
    if not encrypted:
        raise HTTPException(401)
    return crypto.decrypt_session(encrypted)

@app.get("/api/schedule")
async def get_schedule(session: dict = Depends(current_session)):
    api = MireaGrades(session_cookies=session)
    result = await api.get_schedule(days=7)
    return {
        "success": result.success,
        "lessons": [
            {"start": l.start_epoch, "end": l.end_epoch, "name": l.name,
             "teacher": l.teacher, "room": l.room}
            for l in (result.lessons or [])
        ],
    }

Полная версия: examples/fastapi_app.py.

Примеров для QR-сканирования в папке examples/ пока нет — PR приветствуется.

Шифрование сессий

Хранить cookies МИРЭА в БД в открытом виде нельзя — SessionCrypto оборачивает их в Fernet-токен с ключом, выведенным через HKDF из вашего session_keys:

from pymirea.crypto import get_crypto

crypto = get_crypto()
encrypted: str = crypto.encrypt_session(cookies_dict)   # сохраните в БД
decrypted: dict = crypto.decrypt_session(encrypted)     # прочтите из БД

При смене session_keys старые токены становятся нечитаемыми — храните старый ключ в legacy_bot_token для grace-period миграции.

Public API

Имя Назначение
Config / configure(Config) Конфигурация runtime (DI-style, вызывается один раз на старте)
MireaAuth login(), complete_2fa() (алиас submit_otp()), refresh_tokens(), verify_session()
MireaAPI (pymirea.session) mark_attendance(), mark_attendance_for_group(), extract_token_from_qr(), get_attendance_score()
MireaGrades (pymirea.grades) get_schedule(), get_grades(), get_attendance_detail(), self_approve_attendance()
MireaACS get_today_events() — события турникетов
MireaEsports login(), get_slots(), create_booking(), get_my_bookings(), cancel_booking()
SessionCrypto Шифрование/расшифровка cookies (Fernet + HKDF)
AuthChallenge / AuthResult Результаты login-флоу
get_authorization_header(cookies) Bearer-токен из dict сессии
try_refresh_tokens(cookies) Best-effort обновление access-токена
get_token_age_seconds(cookies) Сколько секунд токен живёт

Подробнее в исходниках: pymirea/.

Конфигурация

from pymirea import Config

Config(
    session_keys="base64-32-bytes",     # обязательно
    mirea_proxy="http://proxy:8080",    # опционально, для pulse.mirea.ru (датацентры заблокированы)
    legacy_bot_token=None,              # старый ключ для миграции при ротации
    request_timeout_s=15.0,
    breaker_failure_threshold=5,
    breaker_recovery_s=30.0,
)

Совместимость

  • Python 3.11+
  • Только async (нет sync-обёртки; для скриптов используйте asyncio.run)
  • Любой web-фреймворк: FastAPI, aiohttp, Sanic, Litestar, Quart — pymirea не привязан ни к одному
  • Любая БД для хранения сессий — pymirea даёт только примитивы шифрования

Что pymirea НЕ делает

  • ❌ Не хранит сессии — это задача вашего приложения (БД/Redis/файл)
  • ❌ Не управляет пользователями — у вас своя auth-система
  • ❌ Не предоставляет HTTP-handlers — пишите свои под свой фреймворк
  • ❌ Не парсит сложные нестандартные формы МИРЭА (профили, дипломы — TBD)

Если хочется готовый микросервис — соберите Telegram-бот / FastAPI-сервис на основе примеров.

Внести вклад

Issues и PR приветствуются. Особенно полезно:

  • Тесты для новых сценариев (logout, edge-cases в 2FA, etc.)
  • Поддержка дополнительных эндпоинтов МИРЭА
  • Примеры для других фреймворков (Discord-боты, CLI-tools, ...)

Лицензия

MIT — см. LICENSE.

Metadata

Release files for pymirea 0.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pymirea 0.3.3
File Size Uploaded
pymirea-0.3.3.tar.gz 75.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pymirea 0.3.3
File Interpreter ABI Platform
pymirea-0.3.3-py3-none-any.whl Python 3 none any Details

Total release size: 134.3 kB

Release files / pymirea-0.3.3.tar.gz

Download URL pymirea-0.3.3.tar.gz
Size 75.0 kB
Tags Source
SHA-256 checksum
How to use checksums
4c116bffbf4b49e36e49b46c19103176acbf64662ed8684ac0528d7de35c0b0f
BLAKE2b-256 checksum
How to use checksums
935853ed0594cbc32ea336385705e34816d1bacba8717d2041d585b5610105ca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 29, 2026.

Transparency log

Release files / pymirea-0.3.3-py3-none-any.whl

Download URL pymirea-0.3.3-py3-none-any.whl
Size 59.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bc4721ce9dec193ea275dfdea7c5a72b5db40706d2e4c4b19e3bd7178b1fb598
BLAKE2b-256 checksum
How to use checksums
8e64646982f4404c036ffb5d21f13d6078e8c6b6f8f44b4153a8ff7851142865
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.3 This release

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page