示例#1
0
class SubmissionResponse(ChisubmitAPIObject):
    
    _api_attributes = {
                       "submission": Attribute(name="registration", 
                                               attrtype=APIObjectType(Submission), 
                                               editable=False),  
                                              
                       "extensions_before": Attribute(name="extensions_before", 
                                                      attrtype=APIIntegerType, 
                                                      editable=False),  

                       "extensions_after": Attribute(name="extensions_after", 
                                                     attrtype=APIIntegerType, 
                                                     editable=False),  
                       
                       "extensions_needed": Attribute(name="extensions_needed", 
                                                     attrtype=APIIntegerType, 
                                                     editable=False),                         

                       "extensions_override": Attribute(name="extensions_override", 
                                                     attrtype=APIIntegerType, 
                                                     editable=False),  

                       "in_grace_period": Attribute(name="in_grace_period", 
                                                    attrtype=APIBooleanType, 
                                                    editable=True)                    
                       }    
    
    _api_relationships = { }
示例#2
0
class Submission(ChisubmitAPIObject):

    _api_attributes = {
                       "id": Attribute(name="id", 
                                       attrtype=APIIntegerType, 
                                       editable=False),  
    
                       "extensions_used": Attribute(name="extensions_used", 
                                                    attrtype=APIIntegerType, 
                                                    editable=True),  

                       "commit_sha": Attribute(name="commit_sha", 
                                               attrtype=APIStringType, 
                                               editable=True),  
    
                       "submitted_at": Attribute(name="submitted_at", 
                                                 attrtype=APIDateTimeType, 
                                                 editable=True) ,

                       "submitted_by": Attribute(name="submitted_by", 
                                                 attrtype=APIStringType, 
                                                 editable=True),  
                       
                       "in_grace_period": Attribute(name="in_grace_period", 
                                                    attrtype=APIBooleanType, 
                                                    editable=True)                    
                      }          
    
    _api_relationships = { }    
示例#3
0
class Grader(ChisubmitAPIObject):

    _api_attributes = {
        "url":
        Attribute(name="url", attrtype=APIStringType, editable=False),
        "username":
        Attribute(name="username", attrtype=APIStringType, editable=False),
        "user":
        Attribute(name="user", attrtype=APIObjectType(User), editable=False),
        "git_username":
        Attribute(name="git_username", attrtype=APIStringType, editable=True),
        "git_staging_username":
        Attribute(name="git_staging_username",
                  attrtype=APIStringType,
                  editable=True)
    }

    _api_relationships = {}

    # TODO
    def get_conflicts(self):
        return []
示例#4
0
class Course(ChisubmitAPIObject):
    
    _api_attributes = {
                       "course_id": Attribute(name="course_id", 
                                       attrtype=APIStringType, 
                                       editable=True),    
        
                       "name": Attribute(name="name", 
                                         attrtype=APIStringType, 
                                         editable=True),    

                       "git_server_connstr": Attribute(name="git_server_connstr", 
                                                  attrtype=APIStringType, 
                                                  editable=True),    

                       "git_staging_connstr": Attribute(name="git_staging_connstr", 
                                                  attrtype=APIStringType, 
                                                  editable=True),    
        
                       "git_usernames": Attribute(name="git_usernames", 
                                                  attrtype=APIStringType, 
                                                  editable=True),    
        
                       "git_staging_usernames": Attribute(name="git_staging_usernames", 
                                                          attrtype=APIStringType, 
                                                          editable=True),    
        
                       "extension_policy": Attribute(name="extension_policy", 
                                                     attrtype=APIStringType, 
                                                     editable=True),    
        
                       "default_extensions": Attribute(name="default_extensions", 
                                                       attrtype=APIIntegerType, 
                                                       editable=True),
                      }
    
    _api_relationships = {

                          "instructors": Relationship(name="instructors", 
                                                      reltype=APIObjectType("chisubmit.client.users.Instructor")),  
                       
                          "graders": Relationship(name="graders", 
                                                  reltype=APIObjectType("chisubmit.client.users.Grader")), 

                          "students": Relationship(name="students", 
                                                   reltype=APIObjectType("chisubmit.client.users.Student")), 

                          "assignments": Relationship(name="assignments", 
                                                      reltype=APIObjectType("chisubmit.client.assignment.Assignment")), 

                          "teams": Relationship(name="teams", 
                                                reltype=APIObjectType("chisubmit.client.team.Team")), 
                          
                          }    
                       


    def get_instructors(self):
        """
        :calls: GET /courses/:course/instructors/
        :rtype: List of :class:`chisubmit.client.users.Instructor`
        """
        
        instructors = self.get_related("instructors")
        
        return instructors     

    def get_instructor(self, username):
        """
        :calls: GET /courses/:course/instructors/:instructor
        :rtype: :class:`chisubmit.client.users.Instructor`
        """
        
        headers, data = self._api_client._requester.request(
            "GET",
            "/courses/" + self.course_id + "/instructors/" + username
        )
        return chisubmit.client.users.Instructor(self._api_client, headers, data)
    
    def add_instructor(self, user_or_username, git_username = None, git_staging_username = None):
        """
        :calls: POST /courses/:course/instructors/
        :rtype: :class:`chisubmit.client.users.Instructor`
        """
        
        assert isinstance(user_or_username, (str, unicode)) or isinstance(user_or_username, User) 
        
        if isinstance(user_or_username, (str, unicode)):
            username = user_or_username
        elif isinstance(user_or_username, User):
            username = user_or_username.username
        
        post_data = {"username": username}
        
        if git_username is not None:
            post_data["git_username"] = git_username
        if git_staging_username is not None:
            post_data["git_staging_username"] = git_staging_username
        
        headers, data = self._api_client._requester.request(
            "POST",
            "/courses/" + self.course_id + "/instructors/",
            data = post_data
        )
        return chisubmit.client.users.Instructor(self._api_client, headers, data)    
    
    def remove_instructor(self, user_or_username):
        """
        :calls: DELETE /courses/:course/instructors/:username
        :rtype: None
        """
        
        assert isinstance(user_or_username, (str, unicode)) or isinstance(user_or_username, User) or isinstance(user_or_username, chisubmit.client.users.Instructor)
        
        if isinstance(user_or_username, (str, unicode)):
            username = user_or_username
        elif isinstance(user_or_username, User):
            username = user_or_username.username
        elif isinstance(user_or_username, chisubmit.client.users.Instructor):
            username = user_or_username.user.username
        
        _ = self._api_client._requester.request(
            "DELETE",
            "/courses/" + self.course_id + "/instructors/" + username
        )
        return None
    
    def get_graders(self):
        """
        :calls: GET /courses/:course/graders/
        :rtype: List of :class:`chisubmit.client.users.Grader`
        """
        
        graders = self.get_related("graders")
        
        return graders     

    def get_grader(self, username):
        """
        :calls: GET /courses/:course/graders/:grader
        :rtype: :class:`chisubmit.client.users.Grader`
        """
        
        headers, data = self._api_client._requester.request(
            "GET",
            "/courses/" + self.course_id + "/graders/" + username
        )
        return chisubmit.client.users.Grader(self._api_client, headers, data)    
    
    def add_grader(self, user_or_username, git_username = None, git_staging_username = None):
        """
        :calls: POST /courses/:course/graders/
        :rtype: :class:`chisubmit.client.users.Grader`
        """
        
        assert isinstance(user_or_username, (str, unicode)) or isinstance(user_or_username, User) 
        
        if isinstance(user_or_username, (str, unicode)):
            username = user_or_username
        elif isinstance(user_or_username, User):
            username = user_or_username.username
        
        post_data = {"username": username }
        
        if git_username is not None:
            post_data["git_username"] = git_username
        if git_staging_username is not None:
            post_data["git_staging_username"] = git_staging_username
        
        headers, data = self._api_client._requester.request(
            "POST",
            "/courses/" + self.course_id + "/graders/",
            data = post_data
        )
        return chisubmit.client.users.Grader(self._api_client, headers, data)        
    
    def remove_grader(self, user_or_username):
        """
        :calls: DELETE /courses/:course/graders/:username
        :rtype: None
        """
        
        assert isinstance(user_or_username, (str, unicode)) or isinstance(user_or_username, User) or isinstance(user_or_username, chisubmit.client.users.Grader)
        
        if isinstance(user_or_username, (str, unicode)):
            username = user_or_username
        elif isinstance(user_or_username, User):
            username = user_or_username.username
        elif isinstance(user_or_username, chisubmit.client.users.Grader):
            username = user_or_username.user.username
        
        _ = self._api_client._requester.request(
            "DELETE",
            "/courses/" + self.course_id + "/graders/" + username
        )
        return None
        
    
    def get_students(self):
        """
        :calls: GET /courses/:course/students/
        :rtype: List of :class:`chisubmit.client.users.Student`
        """
        
        students = self.get_related("students")
        
        return students     
    
    def get_student(self, username):
        """
        :calls: GET /courses/:course/students/:grader
        :rtype: :class:`chisubmit.client.users.Student`
        """
        
        headers, data = self._api_client._requester.request(
            "GET",
            "/courses/" + self.course_id + "/students/" + username
        )
        return chisubmit.client.users.Student(self._api_client, headers, data)        
    
    def add_student(self, user_or_username, git_username = None, extensions = None, dropped = None):
        """
        :calls: POST /courses/:course/students/
        :rtype: :class:`chisubmit.client.users.Student`
        """
        
        assert isinstance(user_or_username, (str, unicode)) or isinstance(user_or_username, User) 
        
        if isinstance(user_or_username, (str, unicode)):
            username = user_or_username
        elif isinstance(user_or_username, User):
            username = user_or_username.username
        
        post_data = {"username": username }
        
        if git_username is not None:
            post_data["git_username"] = git_username
        if extensions is not None:
            post_data["extensions"] = extensions
        if dropped is not None:
            post_data["dropped"] = dropped
                    
        headers, data = self._api_client._requester.request(
            "POST",
            "/courses/" + self.course_id + "/students/",
            data = post_data
        )
        return chisubmit.client.users.Student(self._api_client, headers, data)       
    
    def remove_student(self, user_or_username):
        """
        :calls: DELETE /courses/:course/students/:username
        :rtype: None
        """
        
        assert isinstance(user_or_username, (str, unicode)) or isinstance(user_or_username, User) or isinstance(user_or_username, chisubmit.client.users.Student)
        
        if isinstance(user_or_username, (str, unicode)):
            username = user_or_username
        elif isinstance(user_or_username, User):
            username = user_or_username.username
        elif isinstance(user_or_username, chisubmit.client.users.Student):
            username = user_or_username.user.username
        
        _ = self._api_client._requester.request(
            "DELETE",
            "/courses/" + self.course_id + "/students/" + username
        )
        return None      
    
    def get_assignments(self, include_rubric = False):
        """
        :calls: GET /courses/:course/assignments/
        :rtype: List of :class:`chisubmit.client.assignment.Assignment`
        """
        
        include = []
        
        if include_rubric:
            include.append("rubric")
           
        if len(include) > 0:
            params = {"include": include}
        else:
            params = None
        
        assignments = self.get_related("assignments", params = params)
        
        return assignments             
    
    def get_assignment(self, assignment_id, include_rubric = False):
        """
        :calls: GET /courses/:course/assignments/:assignment/
        :rtype: List of :class:`chisubmit.client.assignment.Assignment`
        """
        
        include = []
        
        if include_rubric:
            include.append("rubric")
           
        if len(include) > 0:
            params = {"include": include}
        else:
            params = None        
        
        headers, data = self._api_client._requester.request(
            "GET",
            "/courses/" + self.course_id + "/assignments/" + assignment_id,
            params = params
        )
        return chisubmit.client.assignment.Assignment(self._api_client, headers, data)
    
    def create_assignment(self, assignment_id, name, deadline, min_students = None, max_students = None):
        """
        :calls: POST /courses/:course/assignments/
        :param assignment_id: string
        :param name: string
        :param deadline: string
        :param min_students: int
        :param max_students: int
        :rtype: :class:`chisubmit.client.assignment.Assignment`
        """
        assert isinstance(assignment_id, (str, unicode)), assignment_id
        assert isinstance(deadline, (str, unicode)) or isinstance(deadline, datetime.datetime), deadline
        
        # TODO: Convert/validate date
        if isinstance(deadline, (str, unicode)):
            # TODO: validate date
            deadline_str = deadline
        elif isinstance(deadline, datetime.datetime):
            deadline_str = deadline.isoformat(sep=" ")
        
        post_data = {"assignment_id": assignment_id,
                     "name": name,
                     "deadline": deadline_str}
        
        if min_students is not None:
            post_data["min_students"] = min_students
        if max_students is not None:
            post_data["max_students"] = max_students
        
        headers, data = self._api_client._requester.request(
            "POST",
            "/courses/" + self.course_id + "/assignments/",
            data = post_data
        )
        return chisubmit.client.assignment.Assignment(self._api_client, headers, data)    
    
    def get_teams(self, include_students=False, include_assignments=False, include_grades = False):
        """
        :calls: GET /courses/:course/teams/
        :rtype: List of :class:`chisubmit.client.team.Team`
        """
        
        include = []
        
        if include_students:
            include.append("students")

        if include_assignments:
            include.append("assignments")
            
        if include_grades:
            include.append("assignments__grades")            
            
        if len(include) > 0:
            params = {"include": include}
        else:
            params = None
        
        teams = self.get_related("teams", params = params)
        
        return teams             
        
    
    def get_team(self, team_id, include_students=False, include_assignments=False, include_grades = False):
        """
        :calls: GET /courses/:course/teams/
        :rtype: :class:`chisubmit.client.team.Team`
        """
        
        assert isinstance(team_id, (str, unicode)), team_id
        
        include = []
        
        if include_students:
            include.append("students")

        if include_assignments:
            include.append("assignments")
            
        if include_grades:
            include.append("assignments__grades")            

        if len(include) > 0:
            params = {"include": include}
        else:
            params = None        
        
        headers, data = self._api_client._requester.request(
            "GET",
            self.teams_url + team_id,
            params = params
        )
        return chisubmit.client.team.Team(self._api_client, headers, data)    
    
    def create_team(self, team_id, extensions = None, active = None):
        """
        :calls: POST /courses/:course/teams/
        :param name: string
        :param extensions: int
        :param active: bool
        :rtype: :class:`chisubmit.client.team.Team`
        """
        assert isinstance(team_id, (str, unicode)), team_id

        post_data = { "team_id": team_id }
        
        if extensions is not None:
            post_data["extensions"] = extensions
        if active is not None:
            post_data["active"] = active
        
        headers, data = self._api_client._requester.request(
            "POST",
            self.teams_url,
            data = post_data
        )
        return chisubmit.client.team.Team(self._api_client, headers, data)        
示例#5
0
class Team(ChisubmitAPIObject):

    _api_attributes = {
        "team_id":
        Attribute(name="team_id", attrtype=APIStringType, editable=True),
        "extensions":
        Attribute(name="extensions", attrtype=APIIntegerType, editable=True),
        "active":
        Attribute(name="active", attrtype=APIBooleanType, editable=True),
    }

    _api_relationships = {
        "students":
        Relationship(name="students", reltype=APIObjectType(TeamMember)),
        "assignments":
        Relationship(name="assignments", reltype=APIObjectType(Registration)),
    }

    def get_team_members(self):
        """
        :calls: GET /courses/:course/teams/:team/students/
        :rtype: List of :class:`chisubmit.client.team.TeamMember`
        """

        team_members = self.get_related("students")

        return team_members

    def get_team_member(self, username):
        """
        :calls: GET /courses/:course/teams/:team/students/:username
        :rtype: :class:`chisubmit.client.team.TeamMember`
        """

        assert isinstance(username, (str, unicode)), username

        headers, data = self._api_client._requester.request(
            "GET", self.students_url + username)
        return TeamMember(self._api_client, headers, data)

    def add_team_member(self, user_or_username, confirmed=None):
        """
        :calls: POST /courses/:course/teams/:team/students/
        :rtype: :class:`chisubmit.client.team.TeamMember`
        """

        assert isinstance(user_or_username, (str, unicode)) or isinstance(
            user_or_username, User)

        if isinstance(user_or_username, (str, unicode)):
            username = user_or_username
        elif isinstance(user_or_username, User):
            username = user_or_username.username

        post_data = {"username": username}

        if confirmed is not None:
            post_data["confirmed"] = confirmed

        headers, data = self._api_client._requester.request("POST",
                                                            self.students_url,
                                                            data=post_data)
        return TeamMember(self._api_client, headers, data)

    def get_assignment_registrations(self):
        """
        :calls: GET /courses/:course/teams/:team/assignments/
        :rtype: List of :class:`chisubmit.client.team.Registration`
        """

        registrations = self.get_related("assignments")

        return registrations

    def get_assignment_registration(self, assignment_id):
        """
        :calls: GET /courses/:course/teams/:team/assignments/:assignment
        :rtype: :class:`chisubmit.client.team.Registration`
        """

        assert isinstance(assignment_id, (str, unicode)), assignment_id

        headers, data = self._api_client._requester.request(
            "GET", self.assignments_url + assignment_id)
        return Registration(self._api_client, headers, data)

    def add_assignment_registration(self,
                                    assignment_or_assignment_id,
                                    grader_or_grader_username=None):
        """
        :calls: POST /courses/:course/teams/:team/assignments/
        :rtype: :class:`chisubmit.client.team.Registration`
        """

        assert isinstance(assignment_or_assignment_id,
                          (str, unicode)) or isinstance(
                              assignment_or_assignment_id, Assignment)
        assert grader_or_grader_username is None or isinstance(
            grader_or_grader_username,
            (str, unicode)) or isinstance(grader_or_grader_username, Grader)

        if isinstance(assignment_or_assignment_id, (str, unicode)):
            assignment_id = assignment_or_assignment_id
        elif isinstance(assignment_or_assignment_id, User):
            assignment_id = assignment_or_assignment_id.assignment_id

        post_data = {"assignment_id": assignment_id}

        if grader_or_grader_username is not None:
            if isinstance(grader_or_grader_username, (str, unicode)):
                grader_username = grader_or_grader_username
            elif isinstance(grader_or_grader_username, User):
                grader_username = grader_or_grader_username.user.username
            post_data["grader_username"] = grader_username

        headers, data = self._api_client._requester.request(
            "POST", self.assignments_url, data=post_data)
        return Registration(self._api_client, headers, data)
示例#6
0
class Registration(ChisubmitAPIObject):

    _api_attributes = {
        "assignment_id":
        Attribute(name="assignment_id", attrtype=APIStringType,
                  editable=False),
        "assignment":
        Attribute(name="assignment",
                  attrtype=APIObjectType(Assignment),
                  editable=False),
        "grader_username":
        Attribute(name="grader_username",
                  attrtype=APIStringType,
                  editable=True),
        "grader":
        Attribute(name="grader",
                  attrtype=APIObjectType(Grader),
                  editable=False),
        "final_submission_id":
        Attribute(name="final_submission_id",
                  attrtype=APIIntegerType,
                  editable=True),
        "final_submission":
        Attribute(name="final_submission",
                  attrtype=APIObjectType(Submission),
                  editable=False),
        "grade_adjustments":
        Attribute(name="grade_adjustments",
                  attrtype=APIDictType(APIDecimalType),
                  editable=True),
    }

    _api_relationships = {
        "submissions":
        Relationship(name="submissions", reltype=APIObjectType(Submission)),
        "grades":
        Relationship(name="grades", reltype=APIObjectType(Grade)),
    }

    def get_submissions(self):
        """
        :calls: GET /courses/:course/teams/:team/assignments/:assignment/submissions
        :rtype: List of :class:`chisubmit.client.team.Submission`
        """

        submissions = self.get_related("submissions")

        return submissions

    def get_submission(self, submission):
        """
        :calls: GET /courses/:course/teams/:team/assignments/:assignment/submissions/:submission
        :rtype: :class:`chisubmit.client.team.Submission`
        """

        assert isinstance(submission, int), submission

        headers, data = self._api_client._requester.request(
            "GET", self.submissions_url + str(submission))
        return Submission(self._api_client, headers, data)

    def add_submission(self,
                       commit_sha,
                       extensions_used=None,
                       submitted_at=None):
        """
        :calls: POST /courses/:course/teams/:team/assignments/:assignment/submissions/
        :rtype: :class:`chisubmit.client.team.Submission`
        """

        post_data = {"commit_sha": commit_sha}

        if extensions_used is not None:
            post_data["extensions_used"] = extensions_used
        if submitted_at is not None:
            post_data["submitted_at"] = submitted_at

        headers, data = self._api_client._requester.request(
            "POST", self.submissions_url, data=post_data)
        return Submission(self._api_client, headers, data)

    def get_grades(self):
        """
        :calls: GET /courses/:course/teams/:team/assignments/:assignment/grades/
        :rtype: List of :class:`chisubmit.client.team.Grade`
        """

        grades = self.get_related("grades")

        return grades

    def add_grade(self, rubric_component, points=None):
        """
        :calls: POST /courses/:course/teams/:team/assignments/:assignment/grades/
        :rtype: :class:`chisubmit.client.team.Grade`
        """

        post_data = {"rubric_component_id": rubric_component.id}

        if points is not None:
            post_data["points"] = points

        headers, data = self._api_client._requester.request("POST",
                                                            self.grades_url,
                                                            data=post_data)
        return Grade(self._api_client, headers, data)

    def submit(self, commit_sha, extensions_override=None, dry_run=False):
        """
        :calls: POST /courses/:course/teams/:team/assignments/:assignment/submit/
        :rtype: :class:`chisubmit.client.team.Submission`
        """

        post_data = {"commit_sha": commit_sha}

        if dry_run:
            qs = "?dry_run=true"
        else:
            qs = ""

        if extensions_override is not None:
            post_data["extensions_override"] = extensions_override

        headers, data = self._api_client._requester.request("POST",
                                                            self.url +
                                                            "/submit" + qs,
                                                            data=post_data)
        return SubmissionResponse(self._api_client, headers, data)

    def cancel(self):
        """
        :calls: DELETE /courses/:course/teams/:team/assignments/:assignment/
        :rtype: None
        """
        self.delete()

    def set_grade(self, rubric_component, points):
        if points < 0 or points > rubric_component.points:
            raise ValueError(
                "Invalid grade value %.2f ('%s' must be 0 <= x <= %.2f)" %
                (points, rubric_component.description,
                 rubric_component.points))

        grades = self.get_grades()
        grade = [
            g for g in grades if g.rubric_component_id == rubric_component.id
        ]

        if len(grade) == 0:
            self.add_grade(rubric_component, points)
        elif len(grade) == 1:
            grade[0].points = points
        else:
            msg = "Server returned more than one grade for '%s' in %s. " % (
                rubric_component.description, self.assignment.assignment_id)
            msg += "This should not happen. Please contact the chisubmit administrator."

            raise Exception(msg)

    def get_total_penalties(self):
        if self.grade_adjustments is None:
            return 0.0
        else:
            return sum([v for v in self.grade_adjustments.values() if v < 0.0])

    def get_total_bonuses(self):
        if self.grade_adjustments is None:
            return 0.0
        else:
            return sum(
                [v for v in self.grade_adjustments.values() if v >= 0.0])

    def get_total_adjustments(self):
        if self.grade_adjustments is None:
            return 0.0
        else:
            return sum([v for v in self.grade_adjustments.values()])

    def get_total_grade(self):
        grades = self.get_grades()

        return sum([g.points for g in grades]) + self.get_total_adjustments()

    def get_grading_branch_name(self):
        return self.assignment.assignment_id + "-grading"

    def is_ready_for_grading(self):
        if self.final_submission is None:
            return False
        else:
            return is_submission_ready_for_grading(
                assignment_deadline=self.assignment.deadline,
                submission_date=self.final_submission.submitted_at,
                extensions_used=self.final_submission.extensions_used)
示例#7
0
class Assignment(ChisubmitAPIObject):

    _api_attributes = {
        "assignment_id":
        Attribute(name="assignment_id", attrtype=APIStringType, editable=True),
        "name":
        Attribute(name="name", attrtype=APIStringType, editable=True),
        "deadline":
        Attribute(name="deadline", attrtype=APIDateTimeType, editable=True),
        "grace_period":
        Attribute(name="grace_period",
                  attrtype=APITimeDeltaType,
                  editable=True),
        "min_students":
        Attribute(name="min_students", attrtype=APIIntegerType, editable=True),
        "max_students":
        Attribute(name="max_students", attrtype=APIIntegerType, editable=True),
    }

    _api_relationships = {
        "rubric":
        Relationship(name="instructors",
                     reltype=APIObjectType(RubricComponent)),
    }

    def get_rubric_components(self):
        """
        :calls: GET /courses/:course/assignments/:assignment/rubric
        :rtype: List of :class:`chisubmit.client.assignment.RubricComponent`
        """

        rubric_components = self.get_related("rubric")

        return rubric_components

    def create_rubric_component(self, description, points, order=None):
        """
        :calls: POST /courses/:course/assignments/:assignment/rubric/
        :param description: string
        :param points: float
        :param order: int
        :rtype: :class:`chisubmit.client.assignment.RubricComponent`
        """
        assert isinstance(description, (str, unicode)), description

        post_data = {"description": description, "points": points}

        if order is not None:
            post_data["order"] = order

        headers, data = self._api_client._requester.request("POST",
                                                            self.rubric_url,
                                                            data=post_data)
        return RubricComponent(self._api_client, headers, data)

    def register(self, students):
        """
        :calls: POST /courses/:course/assignments/:assignment/register
        :param students: list of string
        :rtype: :class:`chisubmit.client.assignment.RegistrationResponse`
        """
        assert isinstance(students, (list, tuple)), students

        post_data = {"students": students}

        headers, data = self._api_client._requester.request("POST",
                                                            self.url +
                                                            "/register",
                                                            data=post_data)
        return RegistrationResponse(self._api_client, headers, data)