def print_canvas_courses(args): """Show a list of current teacher's courses from Canvas via the API. """ g = Grader(args.path) if 'canvas-token' not in g.config: logger.error( "canvas-token configuration is missing! Please set the Canvas API access " "token before attempting to use Canvas API functionality") print("Canvas course listing failed: missing Canvas API access token.") return canvas = CanvasAPI(g.config["canvas-token"], g.config["canvas-host"]) courses = canvas.get_instructor_courses() if not courses: print("No courses found where current user is a teacher.") return output = PrettyTable(["#", "ID", "Name"]) output.align["Name"] = "l" for ix, c in enumerate(sorted(courses, key=lambda c: c['id'], reverse=True)): output.add_row((ix + 1, c['id'], c['name'])) print(output)
def print_canvas_courses(conf, _): """Show a list of current teacher's courses from Canvas via the API. """ if 'canvas-token' not in conf: logger.error( "canvas-token configuration is missing! Please set the Canvas API access " "token before attempting to use Canvas API functionality") print("Canvas course listing failed: missing Canvas API access token.") return canvas = CanvasAPI(conf["canvas-token"], conf["canvas-host"]) try: courses = canvas.get_instructor_courses() except AuthenticationFailed as e: logger.debug(e) logger.error( "Canvas authentication failed. Is your token missing or expired?") return if not courses: print("No courses found where current user is a teacher.") return output = PrettyTable(["#", "ID", "Name"]) output.align["Name"] = "l" for ix, c in enumerate(sorted(courses, key=lambda c: c['id'], reverse=True)): output.add_row((ix + 1, c['id'], c['name'])) print(output)
def test_retries_on_5xx(self): self.mock_get.side_effect = HTTPError(response=FakeResponse(503)) api = CanvasAPI("test token", "mst.instructure.com") with self.assertRaises(HTTPError): api.get_instructor_courses() self.assertEqual(5, self.mock_get.call_count)
def import_from_canvas(conf, backend, args): """Imports students from a Canvas course to the roster. """ if 'canvas-token' not in conf: logger.error( "canvas-token configuration is missing! Please set the Canvas API access " "token before attempting to import users from Canvas") print("Import from canvas failed: missing Canvas API access token.") return course_id = args.id section = args.section force = args.force username_column = args.username_column canvas = CanvasAPI(conf["canvas-token"], conf["canvas-host"]) try: students = canvas.get_course_students(course_id) if "canvas-courses" not in conf: conf["canvas-courses"] = [] add_to_courses(conf["canvas-courses"], int(course_id), section) except AuthenticationFailed as e: logger.debug(e) logger.error( "Canvas authentication failed. Is your token missing or expired?") return except CourseNotFound as e: logger.debug(e) logger.error( "Course ID %s not found. Make sure to use the ID, not the row number.", course_id) return for s in students: logger.debug(s) if username_column not in s or not s[username_column]: logger.error("Could not get username for %s", s['sortable_name']) try: add_to_roster(conf, backend, conf.roster, s['sortable_name'], s[username_column], section, force, s['id']) except DuplicateUserError: logger.warning("User %s is already in the roster, skipping", s[username_column]) print("Imported {} students.".format(len(students)))
def import_from_canvas(args): """Imports students from a Canvas course to the roster. """ g = Grader(args.path) if 'canvas-token' not in g.config: logger.error( "canvas-token configuration is missing! Please set the Canvas API access " "token before attempting to import users from Canvas") print("Import from canvas failed: missing Canvas API access token.") return course_id = args.id force = args.force canvas = CanvasAPI(g.config["canvas-token"], g.config["canvas-host"]) students = canvas.get_course_students(course_id) for s in students: if 'sis_user_id' not in s: logger.error("Could not get username for %s", s['sortable_name']) if not force: for student in g.config.roster: if student['name'] == s['sortable_name']: logger.warning( "User %s is already in the roster, skipping", s['sis_user_id']) break else: g.config.roster.append({ 'name': s['sortable_name'], 'id': s['sis_user_id'] }) else: g.config.roster.append({ 'name': s['sortable_name'], 'id': s['sis_user_id'] }) print("Imported {} students.".format(len(students))) g.config.save()
def get_api(cls, conf: Config) -> CanvasAPI: if not cls._api: if "canvas-token" not in conf: logger.error( "canvas-token configuration is missing! Please set the Canvas API access " "token before attempting to use Canvas API functionality") print( "Canvas course listing failed: missing Canvas API access token." ) raise KeyError cls._api = CanvasAPI(conf["canvas-token"], conf["canvas-host"]) return cls._api
def test_failed_dns(self): self.mock_get.side_effect = HTTPError("Name or service not known") api = CanvasAPI("test token", "mst.instructure.com") with self.assertRaises(NameResolutionFailed): api.get_instructor_courses() with self.assertRaises(NameResolutionFailed): api.get_course_students(420)
def lookup_canvas_ids( conf: Config, canvas: CanvasAPI, hw_name: str) -> Tuple[Dict[str, int], Dict[str, int]]: """ Retrieves the list of internal Canvas IDs for a given assignment and the relevant sections :param hw_name: the name of the homework assignment to search for on Canvas :return: "section_ids", a map of section names/identifiers onto Canvas internal course IDs and "assignment_ids", a map of section names/identifiers onto the Canvas internal assignment IDs for a given assignment """ if "canvas-courses" not in conf or not conf["canvas-courses"]: logger.error( 'canvas-courses configuration is missing! Please use the "assigner canvas import"' "command to associate course IDs with section names") print( "Canvas course listing failed: missing section Canvas course IDs." ) raise CourseNotFound courses = conf["canvas-courses"] section_ids = {course["section"]: course["id"] for course in courses} min_name = re.search(r"[A-Za-z]+\d+", hw_name).group(0) assignment_ids = {} for section, course_id in section_ids.items(): try: canvas_assignments = canvas.get_course_assignments( course_id, min_name) except CourseNotFound: logger.error("Failed to pull assignment list from Canvas") raise if len(canvas_assignments) != 1: logger.warning( "Could not uniquely identify Canvas assignment from name %s and section %s, using first assignment listed", min_name, section, ) assignment_ids[section] = canvas_assignments[0]["id"] return (section_ids, assignment_ids)
def test_course_not_found(self): self.mock_get.side_effect = HTTPError(response=FakeResponse(404)) api = CanvasAPI("test token", "mst.instructure.com") with self.assertRaises(CourseNotFound): api.get_course_students(420)
def test_students_auth_failure(self): self.mock_get.side_effect = HTTPError(response=FakeResponse(401)) api = CanvasAPI("test token", "mst.instructure.com") with self.assertRaises(AuthenticationFailed): api.get_course_students(420)
def test_http_urls_are_httpsified(self): api = CanvasAPI("test token", "http://mst.instructure.com") self.assertEqual("https://mst.instructure.com", api.website_root)