Skip to content

Commit

Permalink
ucfopen#440: added util.py:obj_or_id_or_sis_str, use it in course.py:…
Browse files Browse the repository at this point in the history
…enroll_user to support 'sis_login_id:' syntax
  • Loading branch information
ndegroot committed Nov 1, 2021
1 parent 3f1a71e commit 3b7ba1e
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 1 deletion.
3 changes: 2 additions & 1 deletion canvasapi/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
normalize_bool,
obj_or_id,
obj_or_str,
obj_or_id_or_sis_str
)


Expand Down Expand Up @@ -659,7 +660,7 @@ def enroll_user(self, user, enrollment_type=None, **kwargs):
from canvasapi.enrollment import Enrollment
from canvasapi.user import User

kwargs["enrollment[user_id]"] = obj_or_id(user, "user", (User,))
kwargs["enrollment[user_id]"] = obj_or_id_or_sis_str(user, "user", (User,))

if enrollment_type:
warnings.warn(
Expand Down
44 changes: 44 additions & 0 deletions canvasapi/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,50 @@ def obj_or_str(obj, attr, object_types):
raise TypeError("Parameter {} must be of type {}.".format(obj, obj_type_list))


def obj_or_id_or_sis_str(parameter, param_name, object_types):
"""
Accepts either an int (or long or str representation of an integer) or
a 'sis_*_id:[some id]' format string or an object. If it is an int or
a format string, return it.
If it is an object and the object is of correct type, return the object's id. Otherwise,
throw an exception.
:param parameter: int, str, long, or object
:param param_name: str
:param object_types: tuple
:rtype: int
"""
from canvasapi.user import User

try:
return int(parameter)
except (ValueError, TypeError):
# Special case where 'self' is a valid ID of a User object
if User in object_types and parameter == "self":
return parameter

if (
isinstance(parameter, str)
and parameter.startswith("sis_")
and "_id:" in parameter
):
# not foolproof
return parameter

for obj_type in object_types:
if isinstance(parameter, obj_type):
try:
return int(parameter.id)
except Exception:
break

obj_type_list = ",".join([obj_type.__name__ for obj_type in object_types])
message = "Parameter {} must be of type {} or int or a sis_*_id: format string".format(
param_name, obj_type_list
)
raise TypeError(message)


def get_institution_url(base_url):
"""
Clean up a given base URL.
Expand Down
67 changes: 67 additions & 0 deletions tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
normalize_bool,
obj_or_id,
obj_or_str,
obj_or_id_or_sis_str,
)
from tests import settings
from tests.util import cleanup_file, register_uris
Expand Down Expand Up @@ -471,6 +472,72 @@ def test_obj_or_str_invalid_obj_type(self, m):
with self.assertRaises(TypeError):
obj_or_str("user", "name", (User,))

# obj_or_id_or_sis_str :
# same set of tests as used in the obj_or_id tests,
# added _sis_str_{valid,invalid} tests
def test_obj_or_id_or_sis_str_int(self, m):
user_id = obj_or_id_or_sis_str(1, "user_id", (User,))

self.assertIsInstance(user_id, int)
self.assertEqual(user_id, 1)

def test_obj_or_id_or_sis_str_str_valid(self, m):
user_id = obj_or_id_or_sis_str("1", "user_id", (User,))

self.assertIsInstance(user_id, int)
self.assertEqual(user_id, 1)

def test_obj_or_id_or_sis_str_str_invalid(self, m):
with self.assertRaises(TypeError):
obj_or_id_or_sis_str("1a", "user_id", (User,))

def test_obj_or_id_or_sis_str_sis_str_valid(self, m):
user_id = obj_or_id_or_sis_str("sis_login_id:a_login_id", "user_id", (User,))

self.assertEqual(user_id, "sis_login_id:a_login_id")

def test_obj_or_id_or_sis_str_sis_str_invalid(self, m):
with self.assertRaises(TypeError):
obj_or_id_or_sis_str("sys_login_id:a_login_id", "user_id", (User,))

def test_obj_or_id_or_sis_str_obj(self, m):
register_uris({"user": ["get_by_id"]}, m)

user = self.canvas.get_user(1)

user_id = obj_or_id_or_sis_str(user, "user_id", (User,))

self.assertIsInstance(user_id, int)
self.assertEqual(user_id, 1)

def test_obj_or_id_or_sis_str_obj_no_id(self, m):
register_uris({"user": ["course_nickname"]}, m)

nick = self.canvas.get_course_nickname(1)

with self.assertRaises(TypeError):
obj_or_id_or_sis_str(nick, "nickname_id", (CourseNickname,))

def test_obj_or_id_or_sis_str_multiple_objs(self, m):
register_uris({"user": ["get_by_id"]}, m)

user = self.canvas.get_user(1)

user_id = obj_or_id_or_sis_str(user, "user_id", (CourseNickname, User))

self.assertIsInstance(user_id, int)
self.assertEqual(user_id, 1)

def test_obj_or_id_or_sis_str_user_self(self, m):
user_id = obj_or_id_or_sis_str("self", "user_id", (User,))

self.assertIsInstance(user_id, str)
self.assertEqual(user_id, "self")

def test_obj_or_id_or_sis_str_nonuser_self(self, m):
with self.assertRaises(TypeError):
obj_or_id_or_sis_str("self", "user_id", (CourseNickname,))

# get_institution_url()
def test_get_institution_url(self, m):
correct_url = "https://my.canvas.edu"
Expand Down

0 comments on commit 3b7ba1e

Please sign in to comment.