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 Sequence
from .education_weighted_grade_types import GradeComponent, WeightedGrade
from .math_rational import add_rational, multiply_rational, rational, rational_to_integer ← from math.rational ^1.0.0 · built alongside by fune
from .math_round_div import RoundingMode ← 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 weighted_grade(components: Sequence[GradeComponent], decimals: int, mode: RoundingMode) -> WeightedGrade:
"""Weighted percentage across components, summed exactly and rounded once.
Each component adds mark x weight / (out_of x 100) percent: mark/out_of of
the component, times weight/10000 of the whole, times 100 for a percentage.
"""
if len(components) == 0:
raise ValueError("components must not be empty")
if not _is_int(decimals) or decimals < 0 or decimals > 6:
raise ValueError("decimals must be a whole number from 0 to 6, received %s" % (decimals,))
total = rational(0, 1)
weights = 0
for c in components:
if not _is_int(c.out_of) or c.out_of < 1:
raise ValueError("outOf must be a whole number of 1 or more, received %s for %s" % (c.out_of, c.name))
if not _is_int(c.mark) or c.mark < 0 or c.mark > c.out_of:
raise ValueError(
"mark must be a whole number from 0 to outOf (%s), received %s for %s" % (c.out_of, c.mark, c.name)
)
if not _is_int(c.weight_basis_points) or c.weight_basis_points < 0:
raise ValueError(
"weightBasisPoints must be a whole number of 0 or more, received %s for %s"
% (c.weight_basis_points, c.name)
)
weights += c.weight_basis_points
total = add_rational(total, rational(c.mark * c.weight_basis_points, c.out_of * 100))
if weights != 10000:
raise ValueError("weights must add up to 10000 basis points (100%%), received %s" % (weights,))
scaled = rational_to_integer(multiply_rational(total, rational(10**decimals, 1)), mode)
return WeightedGrade(percent=total, scaled=scaled, decimals=decimals)