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 Dict, Optional, Sequence
from .education_gpa_data import DEFAULT_GRADE_POINTS ← this capability’s own data, compiled from data/default-grade-points.json into the same file by fune build
from .education_gpa_types import GpaCourse, GpaResult, GradePoint
from .math_round_div import RoundingMode, 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 gpa(courses: Sequence[GpaCourse], grade_points: Optional[Sequence[GradePoint]], mode: RoundingMode) -> GpaResult:
"""Credit-weighted grade point average in hundredths, rounded once.
Quality points are summed exactly in integers (hundredths x credits), so
the rounding mode the caller names is the only rounding that happens.
"""
table = DEFAULT_GRADE_POINTS if grade_points is None else grade_points
if len(table) == 0:
raise ValueError("gradePoints must not be empty; pass null for the default table")
points: Dict[str, Optional[int]] = {}
for row in table:
if row.grade in points:
raise ValueError('grade "%s" appears twice in gradePoints' % (row.grade,))
if row.points is not None and (not _is_int(row.points) or row.points < 0):
raise ValueError(
'points must be whole hundredths of 0 or more, received %s for grade "%s"' % (row.points, row.grade)
)
points[row.grade] = row.points
quality_points = 0
gpa_credits = 0
excluded_credits = 0
for course in courses:
if not _is_int(course.credits) or course.credits < 0:
raise ValueError("credits must be a whole number of 0 or more, received %s" % (course.credits,))
if course.grade not in points:
raise ValueError('grade "%s" is not in the grade-point table' % (course.grade,))
p = points[course.grade]
if p is None:
excluded_credits += course.credits
else:
quality_points += p * course.credits
gpa_credits += course.credits
# Validate the mode even when there is nothing to divide.
round_div(0, 1, mode)
return GpaResult(
gpa=None if gpa_credits == 0 else round_div(quality_points, gpa_credits, mode),
quality_points=quality_points,
gpa_credits=gpa_credits,
excluded_credits=excluded_credits,
)