Adapter layer for .rost — converts any data source to canonical JSON
Project description
rost-io
Adapter layer for the rost roster scheduling language.
Converts any data source into canonical rost JSON schemas, ready to feed into the .rost compiler.
Powered by Polars — fast DataFrames backed by Apache Arrow, with native Parquet I/O and Excel via fastexcel (calamine), SQL via connectorx.
Installation
pip install rost-io
No extras needed — Polars, fastexcel, and connectorx are all core dependencies.
Schemas (v0.2)
| Schema | Version | Description |
|---|---|---|
rost/staff/v1 |
core | People, their IDs and tags |
rost/leave/v1 |
core | Approved leave / unavailability |
rost/calendar/v1 |
core | Scheduling horizon and public holidays |
rost/solution/v1 |
core | Solver output — assignments per day |
rost/preferences/v1 |
new | Soft shift requests from staff (wants / avoids) |
rost/preassignments/v1 |
new | Manager-pinned shifts (hard constraints in MIP) |
rost/history/v1 |
new | Previous period's roster (fairness continuity) |
solution/v1 is produced by the solver; all others are inputs from adapters.
Adapters
| Adapter | Source | Backend |
|---|---|---|
CsvAdapter |
CSV files | polars.read_csv |
ExcelAdapter |
.xlsx / .xls workbooks |
polars.read_excel + fastexcel (calamine) |
ParquetAdapter |
Parquet files | polars.read_parquet |
DatabaseAdapter |
PostgreSQL, MySQL, SQLite, MSSQL | connectorx → Polars Arrow |
JsonAdapter |
Pre-formatted JSON | stdlib json |
Quick Start
CSV
from rost_io import CsvAdapter, validate_staff
adapter = CsvAdapter("staff.csv")
data = adapter.to_staff_json()
validate_staff(data) # raises jsonschema.ValidationError on failure
print(data)
Excel
from rost_io import ExcelAdapter
adapter = ExcelAdapter(
"roster_data.xlsx",
staff_sheet="Staff",
leave_sheet="Leave",
preferences_sheet="Preferences",
preassignments_sheet="Preassignments",
history_sheet="History",
)
staff = adapter.to_staff_json()
leave = adapter.to_leave_json()
prefs = adapter.to_preferences_json()
preassigns = adapter.to_preassignments_json()
history = adapter.to_history_json(period_start="2026-04-01", period_end="2026-04-30")
Parquet
from rost_io import ParquetAdapter
staff = ParquetAdapter("staff.parquet").to_staff_json()
Database (PostgreSQL, MySQL, SQLite, MSSQL)
from rost_io import DatabaseAdapter
adapter = DatabaseAdapter(
"postgresql://hr:secret@db.hospital.local/staff_db",
people_query="""
SELECT employee_id AS id,
full_name AS display_name,
department AS tags
FROM employees
WHERE active = true
""",
leave_query="""
SELECT employee_id AS person_id,
leave_start AS start,
leave_end AS end,
leave_type AS type
FROM leave_requests
WHERE approved = true
""",
preferences_query="SELECT * FROM shift_preferences",
preassignments_query="SELECT * FROM pinned_assignments",
history_query="SELECT * FROM roster_history WHERE month = '2026-04'",
)
staff = adapter.to_staff_json()
leave = adapter.to_leave_json()
prefs = adapter.to_preferences_json()
history = adapter.to_history_json(period_start="2026-04-01", period_end="2026-04-30")
Schema Details
preferences/v1 — Soft shift requests
{
"schema": "rost/preferences/v1",
"entries": [
{ "person": "alice", "kind": "wants", "shift": "day", "weekday": "fri", "weight": 2.0 },
{ "person": "bob", "kind": "avoids", "shift": "night", "note": "childcare" }
]
}
kind must be "wants" or "avoids".
date (YYYY-MM-DD) or weekday (mon–sun) or shift may each be present independently.
preassignments/v1 — Manager-pinned shifts
{
"schema": "rost/preassignments/v1",
"entries": [
{ "person": "carol", "date": "2026-05-12", "shift": "day", "reason": "training cover" },
{ "person": "dave", "date": "2026-05-13", "shift": "night" }
]
}
These become hard equality constraints (x[person][date][shift] = 1) in the MIP.
history/v1 — Previous period's assignments
{
"schema": "rost/history/v1",
"period_start": "2026-04-01",
"period_end": "2026-04-30",
"assignments": [
{ "person": "alice", "date": "2026-04-01", "shift": "day" }
]
}
Today's solution/v1 output has the same assignments[] shape — use it directly as next month's history.
Validation
from rost_io import (
validate_staff, validate_leave, validate_calendar,
validate_preferences, validate_preassignments, validate_history,
)
validate_preferences(prefs) # raises jsonschema.ValidationError on schema violation
validate_preassignments(preassigns)
validate_history(history)
Custom Adapters
Subclass RostAdapter and implement the methods for your source:
from rost_io import RostAdapter
class MyHrisAdapter(RostAdapter):
def to_staff_json(self) -> dict:
people = fetch_from_api() # your logic here
return {
"schema": "rost/staff/v1",
"people": [{"id": p["emp_id"], "display_name": p["name"], "tags": [], "custom": {}} for p in people],
}
Methods you don't implement raise NotImplementedError with a helpful message.
Roadmap
- Phase 5: Native Rust I/O crate (
rost-io-rs) using polars-rust directly — zero-copy from Arrow to solver IR, no Python layer for batch pipelines.
License
MIT — see LICENSE
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rost_io-0.2.0.tar.gz.
File metadata
- Download URL: rost_io-0.2.0.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
991a0333c5830f0b7b385676bc0a391fe770ccfdd70340bfb3af58822aa58668
|
|
| MD5 |
f3ef44501506cc6a12b3a6853d104442
|
|
| BLAKE2b-256 |
a32398607fa5944d1c1f1823ada6e84bc99440a3b98b4216b5f8d3a33fe70f13
|
File details
Details for the file rost_io-0.2.0-py3-none-any.whl.
File metadata
- Download URL: rost_io-0.2.0-py3-none-any.whl
- Upload date:
- Size: 19.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cec86e47f9fe810dfb65e38520337a6c6c24bd621120691c47e414252cc9990b
|
|
| MD5 |
b14f5e23229972ef6ed67ec11a9443a4
|
|
| BLAKE2b-256 |
34f5ea4463b0fa5f91c1d3ae460bba70eca86d921c9304592aed5a94af5b59c4
|