Skip to main content

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 (monsun) 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rost_io-0.2.0.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rost_io-0.2.0-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

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

Hashes for rost_io-0.2.0.tar.gz
Algorithm Hash digest
SHA256 991a0333c5830f0b7b385676bc0a391fe770ccfdd70340bfb3af58822aa58668
MD5 f3ef44501506cc6a12b3a6853d104442
BLAKE2b-256 a32398607fa5944d1c1f1823ada6e84bc99440a3b98b4216b5f8d3a33fe70f13

See more details on using hashes here.

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

Hashes for rost_io-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cec86e47f9fe810dfb65e38520337a6c6c24bd621120691c47e414252cc9990b
MD5 b14f5e23229972ef6ed67ec11a9443a4
BLAKE2b-256 34f5ea4463b0fa5f91c1d3ae460bba70eca86d921c9304592aed5a94af5b59c4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page