Functional Weave
Code in TypeScript

education.attendance-rate@1.0.1

impl/python.py

2,516 bytes · the Python implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

from typing import Optional

from .dates_add_days import parse_iso_date  ← from dates.add-days ^1.0.0 · built alongside by fune
from .education_attendance_rate_data import ABSENCE_THRESHOLDS, ABSENCE_THRESHOLDS_HISTORY, ABSENCE_THRESHOLDS_HORIZON  ← this capability’s own data, compiled from data/absence-thresholds.json into the same file by fune build
from .education_attendance_rate_types import AttendanceRate
from .math_round_div import round_div  ← from math.round-div ^1.0.0 · built alongside by fune


def _is_int(value: object) -> bool:
    return isinstance(value, int) and not isinstance(value, bool)


def _threshold_on(measure: str, on_date: str) -> Optional[int]:
    for r in ABSENCE_THRESHOLDS:
        if r.measure == measure and on_date >= r.valid_from and (r.valid_to is None or on_date <= r.valid_to):
            return r.basis_points
    return None


def attendance_rate(possible_sessions: int, missed_sessions: int, on_date: str) -> AttendanceRate:
    """Attendance and absence in basis points, and the DfE absence flags.

    The flags compare missed x 10000 with possible x threshold, exactly: a
    rate of 9.996% rounds to 10.00% but is not persistent absence.
    """
    if not _is_int(possible_sessions) or possible_sessions < 1:
        raise ValueError("possibleSessions must be a whole number of 1 or more, received %s" % (possible_sessions,))
    if not _is_int(missed_sessions) or missed_sessions < 0 or missed_sessions > possible_sessions:
        raise ValueError(
            "missedSessions must be a whole number from 0 to possibleSessions (%s), received %s"
            % (possible_sessions, missed_sessions)
        )
    parse_iso_date(on_date)
    persistent = _threshold_on("persistent", on_date)
    if persistent is None:
        if ABSENCE_THRESHOLDS_HISTORY != "full" and ABSENCE_THRESHOLDS_HORIZON is not None and on_date < ABSENCE_THRESHOLDS_HORIZON:
            raise ValueError(
                "no persistent absence definition on %s: this build was installed with history=%s, so it only carries rules from %s. "
                "Reinstall with history=full for earlier years." % (on_date, ABSENCE_THRESHOLDS_HISTORY, ABSENCE_THRESHOLDS_HORIZON)
            )
        raise ValueError("no persistent absence definition on %s" % (on_date,))
    severe = _threshold_on("severe", on_date)
    absence = round_div(missed_sessions * 10000, possible_sessions, "half-up")
    return AttendanceRate(
        attendance_basis_points=10000 - absence,
        absence_basis_points=absence,
        persistently_absent=missed_sessions * 10000 >= possible_sessions * persistent,
        severely_absent=None if severe is None else missed_sessions * 10000 >= possible_sessions * severe,
    )