Skip to main content

tha-edfi-runner

CI codecov PyPI Python pre-commit wheel size

A Tabular Helper API library that wraps the Ed-Fi ODS REST API with a typed, pipeline-friendly interface.

Install

pip install tha-edfi-runner

Quick start

from tha_edfi_runner import ThaEdfiBase, ThaStudentAssessment

# Fetch tokens for each district
base = ThaEdfiBase()
token_rows = base.batch_fetch_tokens(
    district_rows,
    oauth_endpoint="oauth/token",
    account_col="District BK",
)

# POST student assessment payloads
runner = ThaStudentAssessment(api_version="v3")
results = runner.batch_post_payload(
    rows,
    payload_col="payload",
    key_col="Student Assessment BK",
    workers=4,
    commit=True,
)

Auth

Three auth modes are supported — pass exactly one set of credentials:

# OAuth2 client credentials (fetches a token automatically)
ThaEdfiBase(base_url="...", client_id="key", client_secret="secret")

# Pre-fetched bearer token
ThaEdfiBase(base_url="...", bearer_token="eyJ...")

# No auth (valid for ThaEdfiBase construction; _session() will raise)
ThaEdfiBase(base_url="...")

By default, token_url is derived as {base_url}/oauth/token. Override with token_url=.

URL structure

Ed-Fi ODS data endpoints follow the pattern:

{base_url}/data/{api_version}/ed-fi/{resource}

Pass api_version once and the library handles the rest:

runner = ThaStudentAssessment(base_url="https://ods.example.com/api", api_version="v3")
# data calls hit: https://ods.example.com/api/data/v3/ed-fi/studentAssessments
# OAuth token:    https://ods.example.com/api/oauth/token

Multi-district deployments

When each row carries its own URL and token, pass base_url and api_version at the runner level as defaults, then override per-row via column names:

runner = ThaStudentAssessment(api_version="v3")   # default version
results = runner.batch_get_all(
    rows,
    key_col="District BK",
    url_col="targetUrl",          # per-row ODS base URL
    token_col="EdFi Token",       # per-row bearer token
    api_version_col="apiVersion", # per-row override (takes precedence over "v3")
)

Typical workflow

from tha_edfi_runner import ThaEdfiBase, ThaStudentAssessment
from tha_map_runner import ThaMap

# 1. Fetch tokens for each district
base = ThaEdfiBase()
token_rows = base.batch_fetch_tokens(
    district_rows,
    oauth_endpoint="oauth/token",
    account_col="District BK",
    workers=4,
)

# 2. Enrich district rows with tokens
mapper = ThaMap()
enriched = mapper.enrich_rows(
    district_rows,
    source=token_rows,
    mapping={"EdFi Token": "EdFi Token", "token_expires_at": "token_expires_at"},
    row_key="District BK",
    source_key="District BK",
)

# 3. Fetch all assessments across districts
runner = ThaStudentAssessment(api_version="v3")
flat_assessments = runner.batch_get_all(
    enriched,
    key_col="District BK",
    workers=4,
    show_progress=True,
)

# 4. Join back to original rows
enriched = mapper.expand_rows(
    district_rows,
    source=flat_assessments,
    mapping={"Assessment ID": "id", "Score": "scoreResults.result"},
    row_key="District BK",
    source_key="District BK",
)

API

ThaEdfiBase

ThaEdfiBase(
    *,
    base_url="",
    api_version="",
    client_id=None,
    client_secret=None,
    token_url=None,
    bearer_token=None,
)

base.fetch_token()

Fetch a token using this instance's OAuth2 credentials. Returns:

{"token": "eyJ...", "status": None, "message": None}           # success
{"token": None, "status": "error", "message": "auth error: HTTP 401"}  # failure

base.batch_fetch_tokens()

base.batch_fetch_tokens(
    rows,
    *,
    oauth_endpoint,                    # e.g. "oauth/token"
    account_col,                       # deduplication key
    workers=1,
    show_progress=False,
    progress_desc=None,
    skip_statuses=["error", "warning"],
    status_col="row status",
    url_col="targetUrl",
    key_col="oAuthKey",
    secret_col="oAuthSecret",
    token_col="EdFi Token",
    expires_col="token_expires_at",
) -> list[dict]

Returns one record per unique account_col value with token_col and expires_col set. Results stored in base.rows.


ThaStudentAssessment

Inherits ThaEdfiBase. Default endpoint: ed-fi/studentAssessments.

Single methods

runner.post_payload(payload, *, key, endpoint=..., commit=False) -> dict
# {"key": ..., "status": None | "error" | "dry_run", "message": ...}

runner.get_by_id(resource_id, *, endpoint=...) -> dict
# {"id": ..., "status": None | "error", "message": ..., "data": dict | None}

runner.get_all(*, key, endpoint=..., params=None, limit=500, show_progress=False) -> dict
# {"key": ..., "status": None | "error", "message": ..., "data": [dict, ...]}

runner.delete_by_id(resource_id, *, key, endpoint=..., commit=False) -> dict
# {"id": ..., "key": ..., "status": "deleted" | "error" | "dry_run", "message": ...}

All write methods require commit=True to execute — otherwise return status="dry_run".

Batch methods

All batch methods share these common parameters:

rows,
*,
endpoint=...,
workers=1,
show_progress=False,
progress_desc=None,
skip_statuses=["error", "warning"],
status_col="row status",
url_col="targetUrl",
token_col="EdFi Token",
api_version_col=None,           # column holding per-row ODS version (overrides runner api_version)
auth_key_col=None,              # enable reactive re-auth on 401
auth_secret_col=None,
oauth_endpoint=None,
expires_col=None,               # enable proactive re-auth before token expiry

Method-specific required params:

runner.batch_post_payload(rows, *, payload_col, key_col, ..., commit=False) -> list[dict]
runner.batch_get_by_id(rows, *, id_col, ...) -> list[dict]
runner.batch_get_all(rows, *, key_col, ...) -> list[dict]   # flat list; inject key_col into each record
runner.batch_delete_by_id(rows, *, id_col, key_col, ..., commit=False) -> list[dict]

Results stored in runner.rows.

Re-auth

Provide auth_key_col, auth_secret_col, and oauth_endpoint to enable automatic token refresh:

  • Proactive: if expires_col is set and the token has expired, a fresh token is fetched before the call
  • Reactive: if a call returns 401, the token is refreshed once and the call retried

Alternatives

  • requests — HTTP client underlying this library; use directly for full control
  • edfi-client — Ed-Fi-specific client with broader resource coverage

Choose this library when you're already working in the tha-* row-dict pipeline and want Ed-Fi batch operations to follow the same conventions (skip_statuses, commit flag, self.rows, per-row credentials).

License

MIT

Download files

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

Source Distribution

tha_edfi_runner-0.1.9.tar.gz (85.6 kB view details)

Uploaded Source

Built Distribution

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

tha_edfi_runner-0.1.9-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file tha_edfi_runner-0.1.9.tar.gz.

File metadata

  • Download URL: tha_edfi_runner-0.1.9.tar.gz
  • Upload date:
  • Size: 85.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for tha_edfi_runner-0.1.9.tar.gz
Algorithm Hash digest
SHA256 3f8d12544bb6626526dd0dd2b319b5a814add23e604c2cd3644afc6671cb29bf
MD5 6e23dcf2832ac759cad0b7a19843f7f1
BLAKE2b-256 ac3c50ee9159fb55aea194cb14e863f49b1b8f6d81ba3874a958b0cb569483a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for tha_edfi_runner-0.1.9.tar.gz:

Publisher: publish.yml on tha-guy-nate/tha-edfi-runner

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

File details

Details for the file tha_edfi_runner-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: tha_edfi_runner-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 14.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for tha_edfi_runner-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 5d1a7e22edc88db17fffb136ee1ee9594f68abf15a47bd98e2a4c0803f75239a
MD5 ac062d163abcff1eb94a6300207c6f96
BLAKE2b-256 410bcee07b44ab7df16a9e7072082a573d99cb088f881534c9139be0ec8b52db

See more details on using hashes here.

Provenance

The following attestation bundles were made for tha_edfi_runner-0.1.9-py3-none-any.whl:

Publisher: publish.yml on tha-guy-nate/tha-edfi-runner

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 Sentry Error logging StatusPage Status page