Source code for codegrade.models.extended_assignment_extra
"""The module that defines the ``ExtendedAssignmentExtra`` model.
SPDX-License-Identifier: AGPL-3.0-only OR BSD-3-Clause-Clear
"""
from __future__ import annotations
import typing as t
from dataclasses import dataclass, field
import cg_request_args as rqa
from .. import parsers
from ..utils import to_dict
from .assignment_anonymization_algo import AssignmentAnonymizationAlgo
from .assignment_percentage_grading_settings import (
AssignmentPercentageGradingSettings,
)
from .assignment_points_grading_settings import AssignmentPointsGradingSettings
from .cg_ignore_version import CGIgnoreVersion
from .group_set import GroupSet
from .submission_validator_input_data import SubmissionValidatorInputData
[docs]
@dataclass(kw_only=True)
class ExtendedAssignmentExtra:
"""The fields that the full serialization of an assignment adds to the
short one, for every type of assignment.
"""
#: The cginore.
cgignore: t.Optional[t.Union[SubmissionValidatorInputData, str]]
#: The version of the cignore file.
cgignore_version: t.Optional[CGIgnoreVersion]
#: The fixed value for the maximum that can be achieved in a rubric. This
#: can be higher and lower than the actual max. Will be `None` if unset.
fixed_max_rubric_points: t.Optional[float]
#: The maximum grade you can get for this assignment. This is based around
#: the idea that a 10 is a 'perfect' score. So if this value is 12 a user
#: can score 2 additional bonus points. If this value is `None` it is unset
#: and regarded as a 10.
max_grade: float
#: Settings that influence how the grade for a submission can be
#: determined. TODO: Should we also move `max_grade` and/or
#: `fixed_max_rubric_points` to the grading object?
grading: t.Union[
AssignmentPointsGradingSettings, AssignmentPercentageGradingSettings
]
#: The group set of this assignment. This is `None` if this assignment is
#: not a group assignment.
group_set: t.Optional[GroupSet]
#: The LMS providing this LTI assignment.
lms_name: t.Optional[str]
#: The assignment id of the assignment that determines the grader division
#: of this assignment. This will be `null` if you do not have permissions
#: to see this information, or if no such parent is set.
division_parent_id: t.Optional[int]
#: The anonymization algorithm used for this assignment.
anonymized_grading: t.Optional[AssignmentAnonymizationAlgo]
raw_data: t.Optional[t.Dict[str, t.Any]] = field(init=False, repr=False)
data_parser: t.ClassVar[t.Any] = rqa.Lazy(
lambda: rqa.FixedMapping(
rqa.RequiredArgument(
"cgignore",
rqa.Nullable(
parsers.make_union(
parsers.ParserFor.make(SubmissionValidatorInputData),
rqa.SimpleValue.str,
)
),
doc="The cginore.",
),
rqa.RequiredArgument(
"cgignore_version",
rqa.Nullable(rqa.EnumValue(CGIgnoreVersion)),
doc="The version of the cignore file.",
),
rqa.RequiredArgument(
"fixed_max_rubric_points",
rqa.Nullable(rqa.SimpleValue.float),
doc="The fixed value for the maximum that can be achieved in a rubric. This can be higher and lower than the actual max. Will be `None` if unset.",
),
rqa.RequiredArgument(
"max_grade",
rqa.SimpleValue.float,
doc="The maximum grade you can get for this assignment. This is based around the idea that a 10 is a 'perfect' score. So if this value is 12 a user can score 2 additional bonus points. If this value is `None` it is unset and regarded as a 10.",
),
rqa.RequiredArgument(
"grading",
parsers.make_union(
parsers.ParserFor.make(AssignmentPointsGradingSettings),
parsers.ParserFor.make(
AssignmentPercentageGradingSettings
),
),
doc="Settings that influence how the grade for a submission can be determined. TODO: Should we also move `max_grade` and/or `fixed_max_rubric_points` to the grading object?",
),
rqa.RequiredArgument(
"group_set",
rqa.Nullable(parsers.ParserFor.make(GroupSet)),
doc="The group set of this assignment. This is `None` if this assignment is not a group assignment.",
),
rqa.RequiredArgument(
"lms_name",
rqa.Nullable(rqa.SimpleValue.str),
doc="The LMS providing this LTI assignment.",
),
rqa.RequiredArgument(
"division_parent_id",
rqa.Nullable(rqa.SimpleValue.int),
doc="The assignment id of the assignment that determines the grader division of this assignment. This will be `null` if you do not have permissions to see this information, or if no such parent is set.",
),
rqa.RequiredArgument(
"anonymized_grading",
rqa.Nullable(rqa.EnumValue(AssignmentAnonymizationAlgo)),
doc="The anonymization algorithm used for this assignment.",
),
)
)
def to_dict(self) -> t.Dict[str, t.Any]:
res: t.Dict[str, t.Any] = {
"cgignore": to_dict(self.cgignore),
"cgignore_version": to_dict(self.cgignore_version),
"fixed_max_rubric_points": to_dict(self.fixed_max_rubric_points),
"max_grade": to_dict(self.max_grade),
"grading": to_dict(self.grading),
"group_set": to_dict(self.group_set),
"lms_name": to_dict(self.lms_name),
"division_parent_id": to_dict(self.division_parent_id),
"anonymized_grading": to_dict(self.anonymized_grading),
}
return res
@classmethod
def from_dict(
cls: t.Type[ExtendedAssignmentExtra], d: t.Dict[str, t.Any]
) -> ExtendedAssignmentExtra:
parsed = cls.data_parser.try_parse(d)
res = cls(
cgignore=parsed.cgignore,
cgignore_version=parsed.cgignore_version,
fixed_max_rubric_points=parsed.fixed_max_rubric_points,
max_grade=parsed.max_grade,
grading=parsed.grading,
group_set=parsed.group_set,
lms_name=parsed.lms_name,
division_parent_id=parsed.division_parent_id,
anonymized_grading=parsed.anonymized_grading,
)
res.raw_data = d
return res