Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

librus-python-api

Read grades, attendance, homework, timetables and messages from Librus Synergia in Python. This independent, asynchronous client handles login, session recovery, pagination and request limits, returning typed Python objects rather than HTML.

Use it in personal scripts, notification services or application backends. One service can manage multiple logins while keeping their sessions and data separate. It is not an official Librus product.

Requirements: Python 3.13 or newer. Linux and macOS are tested in CI. Persistence and saving attachments require POSIX filesystem features, such as those on Linux or macOS; Windows disk workflows are unsupported.

Status: 1.0.0rc1, a library-only beta prerelease, not stable 1.0 or an MCP cutover. MCP integration, legacy-state migration and broader live qualification remain unfinished. School features depend on what each account can access. See limitations below.

Install

Install the exact candidate from PyPI once its gated publication completes:

python -m pip install librus-python-api==1.0.0rc1

An explicit version selects the prerelease without opting into every prerelease dependency. Before publication, use a checkout or locally built wheel instead. From a checkout, install into a virtual environment:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install .

To install a locally built wheel instead:

python -m pip install ./dist/librus_python_api-1.0.0rc1-py3-none-any.whl

No CLI or background process is installed: import the library in your own program.

First request

Provide your login and password through your application's secret management. The example reads environment variables; the library itself does not discover environment variables or credential files.

You also need an application context key. Generate it once, store it alongside your other application secrets, and reuse it across runs:

python -c 'import secrets; print(secrets.token_hex(32))'

Set LIBRUS_LOGIN, LIBRUS_PASSWORD and LIBRUS_CONTEXT_KEY in your environment. The last variable is the 64-character hex output from that command. Do not use your password as this key. Then run:

import asyncio
import os
from datetime import date

from librus_python_api import AccountCredentials, HomeworkRangeRequest, LibrusService


async def main() -> None:
    accounts = {
        "school": AccountCredentials(
            login=os.environ["LIBRUS_LOGIN"],
            password=os.environ["LIBRUS_PASSWORD"],
        )
    }
    context_key = bytes.fromhex(os.environ["LIBRUS_CONTEXT_KEY"])
    async with LibrusService(accounts, context_key=context_key) as service:
        client = service.account("school")
        profile = await client.student_information()
        print(profile)

        today = date.today()
        homework = await client.homework_range(
            HomeworkRangeRequest(today.replace(day=1), today)
        )
        for item in homework.items:
            print(item.subject, item.topic, item.due_on)


asyncio.run(main())

"school" is your local account alias, not a student ID. Login occurs on the first request. The async context manager closes sessions and outstanding work when it exits. Results are immutable dataclasses; personal fields are omitted from their repr, so access named attributes when displaying data intentionally.

Common tasks

Inside the service context above:

from datetime import timedelta

# School-provided final grades, grouped into typed subject records.
grades = await client.final_grades()
for subject in grades.items:
    print(subject.subject, subject.annual.raw)

# A week always starts on Monday.
today = date.today()
monday = today - timedelta(days=today.weekday())
timetable = await client.timetable(monday)

# Inclusive date window. Neither attendance nor grades computes a GPA.
attendance = await client.attendance_window(today.replace(day=1), today)

# Permit reuse of this account's cached result for up to 60 seconds.
announcements = await client.announcements(max_age_seconds=60)

Collections expose named record tuples, for example homework.items, rather than name-keyed dictionaries. Dates are Python date values where established by the upstream contract. Displayed detail values remain strings; missing or unknown values are not replaced with guessed zeros. Full signatures, result fields and examples are in the API reference.

Multiple accounts

Add more aliases to accounts, then use service.account(alias) for each login. Reuse one service so concurrent calls share its request budget and connection limits. A parent login and a student login are separate contexts even when they refer to the same student. Separate processes need application-level coordination if they share an upstream traffic allowance.

Bounded pagination and errors

from librus_python_api import RequestBudget
from librus_python_api.exceptions import LibrusError, ViewDisabledError

budget = RequestBudget(max_requests=20, timeout_seconds=60)
try:
    batch = await client.messages(limit=25, max_pages=2, budget=budget)
    for message in batch.items:
        print(message.subject)
    # Request another batch with cursor=batch.next_cursor when it is not None.
except ViewDisabledError:
    print("This school has disabled the requested view.")
except LibrusError as error:
    print(f"Request failed: {error.kind.value}")

A budget covers login, queueing and all pages of an operation. Defaults allow 5 requests/second, a burst of 10 and two simultaneous requests across the service. Fresh reads are the default. Unsupported layouts raise typed errors rather than silently returning incomplete data. Cursors detect changes; they are not snapshots.

Messages, files and notifications

  • Message content: opening received content can mark it read. Pass allow_mark_read=True only when your application permits that effect.
  • Sending: prepare a single-use send attempt and obtain approval in your application. An UNKNOWN result must not trigger an automatic resend.
  • Attachments: stream bytes with explicit limits, or use the optional files.publish_attachment() helper to save atomically into an existing directory.
  • Notifications: optional NotificationStore and NotificationWorkflow provide durable checkpoints, pending delivery and explicit acknowledgement.
  • Persistent sends: optional PersistenceStore records confirmations, claims and uncertain outcomes across restarts. These stores require private POSIX directories. Core reads do not create files.

The legacy and modern messaging backends have distinct references and permissions; select one explicitly. See the API reference for complete workflows.

Context keys and upgrading from 0.6

LibrusService now requires context_key, exactly 32 secret random bytes. client.context.identifier is an HMAC-SHA256 pseudonym bound to that key, the alias, login and configured origins. Password changes preserve it. Different application keys produce different identifiers; the identifier is not a login credential or permission token. The separate context.alias is still plain text.

Back up and reuse the key with persistent state. Losing or rotating it changes all context identifiers. Do not treat an empty history under a different key as permission to resend a message. Version 0.7 uses storage and notification archive format 3 and refuses older formats without modifying them. Keep 0.6 stores and their pending/UNKNOWN records for reconciliation; there is no automatic migration. See the upgrade guide before reusing a persistent application.

Loguru is no longer a dependency. For optional diagnostics, pass diagnostic_sink=librus_python_api.diagnostics.logging_sink after importing that function. Configure handlers with Python's standard logging module. You can also pass your own callable; events contain allowlisted timing/outcome fields, not credentials, account aliases or response bodies. The old loguru_sink was removed in 0.7.

Supported features and limitations

Area Available
School data Profile, grades, attendance, timetable, announcements, agenda, homework and completed lessons
Communication Legacy/modern message lists and content, recipient discovery, bounded attachment streams and explicit sending
Application workflows Shared multi-account limits, caching, notification checkpoints, optional durable send/notification stores

Completed lessons may be disabled by the school. Behaviour notes and observation cards are not implemented. Some recipient, archive and receipt layouts remain unqualified; backend acceptance is not proof of delivery. Tests cover supported contracts, not every school or role. Detailed coverage is in the verification log and roadmap.

Development and support

Use a repository checkout for tests and development tools; they are deliberately excluded from published source archives. See CONTRIBUTING.md for setup and offline checks. Report bugs through GitHub Issues and security concerns according to SECURITY.md. Do not attach credentials or raw school data to public reports.

MIT licensed. See LICENSE.

Metadata

Release files for librus-python-api 1.0.0rc1

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

Source distribution (sdist)

Source distribution for librus-python-api 1.0.0rc1
File Size Uploaded
librus_python_api-1.0.0rc1.tar.gz 278.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for librus-python-api 1.0.0rc1
File Interpreter ABI Platform
librus_python_api-1.0.0rc1-py3-none-any.whl Python 3 none any Details

Total release size: 412.9 kB

Release files / librus_python_api-1.0.0rc1.tar.gz

Download URL librus_python_api-1.0.0rc1.tar.gz
Size 278.2 kB
Tags Source
SHA-256 checksum
How to use checksums
7ecbefdba84714dc95080665d4019adbc40c497475856e897d24a51b6433be13
BLAKE2b-256 checksum
How to use checksums
e2b0b9a45808d8c451f505f24c880783a459f25b47d02a0afe4aaf34b9dd8158
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 5, 2026.

Transparency log

Release files / librus_python_api-1.0.0rc1-py3-none-any.whl

Download URL librus_python_api-1.0.0rc1-py3-none-any.whl
Size 134.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c879dcb4fda13314254e0c0d012c9a2981e87f8b7a431247df9c3990a4fbe893
BLAKE2b-256 checksum
How to use checksums
bf7ddcfe4734fe045c67fdf83968bd1378c8f729a3103b7e62bba2c43368ec8a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

1.6.1

2 release files

1.6.0

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.1

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

This release

1.0.0rc1 This release

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