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.1.tar.gz (20.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.1-py3-none-any.whl (29.4 kB view details)

Uploaded Python 3

File details

Details for the file rost_io-0.2.1.tar.gz.

File metadata

  • Download URL: rost_io-0.2.1.tar.gz
  • Upload date:
  • Size: 20.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rost_io-0.2.1.tar.gz
Algorithm Hash digest
SHA256 836f89d69c8e0b76c7525c8a640235a64afe5c26b4159407ebd496c55ed4ab17
MD5 c2e7d4a00ce194bbc1aaac2276911abd
BLAKE2b-256 a95ebeaf15a6aec839125afa59c64909e98813ef41b5a89c86a5912e1aa565bb

See more details on using hashes here.

Provenance

The following attestation bundles were made for rost_io-0.2.1.tar.gz:

Publisher: release.yml on Bpi031/rost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rost_io-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: rost_io-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 29.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rost_io-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4f17539a031d35e044fe520bae4a581541779dd41710d3bb54b95de4dde477b8
MD5 47e2f745e0563f87a30123cdecfd9c7b
BLAKE2b-256 ca2b8576a1d371f7a963ff0da7c59a9cd55ec0c549865bdc6a9e024eefbbff2a

See more details on using hashes here.

Provenance

The following attestation bundles were made for rost_io-0.2.1-py3-none-any.whl:

Publisher: release.yml on Bpi031/rost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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