Repository: ucfopen/canvasapi
Pull request #613 (2023-04-21 22:50:14)

Release v3.1.0
🎉 

## [3.1.0] - 2023-04-21

### New Endpoint Coverage

- Account Calendars (Thanks, [@dmols](https://github.com/dmols))
    - List available account calendars
    - Get a single account calendar
    - Update a calendar's visibility
    - Update many calendars' visibility
    - List all account calendars
- Enrollments (Thanks, [@svanderwulp](https://github.com/svanderwulp))
    - Accept Course Invitation
    - Reject Course Invitation
- File (Thanks, [@bennettscience](https://github.com/bennettscience))
    - Update File
- JWTs (Thanks [@dmols](https://github.com/dmols))
    - Create JWTs
    - Refresh JWTs
- Moderation Grading (Moderation Set)
    - List students selected for moderation
    - Select students for moderation
- Query Course Events (Thanks, [@dmols](https://github.com/dmols))
    - Query by course
    - Query by account
- Rubrics (Thanks, [@bennettscience](https://github.com/bennettscience))
    - Create, Update, and Delete Rubric Assessments
    - Create a Rubric Association
- Users
    - Terminate all user sessions (Thanks, [@lucas-salas](https://github.com/lucas-salas))


Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9d0cb7b..994832d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,6 +1,6 @@
 repos:
-  - repo: https://github.com/ambv/black
-    rev: stable
+  - repo: https://github.com/psf/black
+    rev: 23.3.0
     hooks:
     - id: black
-      language_version: python3.7
+      language_version: python3
diff --git a/AUTHORS.md b/AUTHORS.md
index f82fa2e..3b38cd8 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -33,6 +33,7 @@ Patches and Suggestions
 - Damian Sweeney [@damianfs](https://github.com/damianfs)
 - Daniel Brinkman [@DanBrink91](https://github.com/DanBrink91)
 - Daniel Grobani [@dgrobani](https://github.com/dgrobani)
+- Daniel Molares [@dmols](https://github.com/dmols)
 - David Warden [@dfwarden](https://github.com/dfwarden)
 - Davis Goff [@Goff-Davis](https://github.com/Goff-Davis)
 - Deundre Williams [@deundrewilliams](https://github.com/deundrewilliams)
@@ -60,13 +61,16 @@ Patches and Suggestions
 - Kenny Perez [@kennygperez](https://github.com/kennygperez)
 - [@kensler](https://github.com/kensler)
 - Lawrence Oks [@ljoks](https://github.com/ljoks)
+- Lee Fent [@lafent](https://github.com/lafent)
 - Leonard Camacho [@lcamacho](https://github.com/lcamacho)
+- Lucas Salas [@lucas-salas](https://github.com/lucas-salas)
 - Mark Lalor [@MarkLalor](https://github.com/MarkLalor)
 - Markus [@elec3647](https://github.com/elec3647)
 - Matthew Fedder [@matthewf-ucsd](https://github.com/matthewf-ucsd)
 - Matthew Jones [@jonespm](https://github.com/jonespm)
 - Michael Phelps [@nottheswimmer](https://github.com/nottheswimmer)
 - Mike Nahmias [@Mike-Nahmias](https://github.com/Mike-Nahmias)
+- Mike Suhan [@mikesuhan](https://github.com/mikesuhan)
 - Nathan Dabu [@nathaned](https://github.com/nathaned)
 - Petar Nikolovski [@petarGitNik](https://github.com/petarGitNik)
 - Philip Austin [@phaustin](https://github.com/phaustin)
@@ -79,6 +83,7 @@ Patches and Suggestions
 - Stephen Woosley [@stephenwoosley](https://github.com/stephenwoosley)
 - Steven Bell [@stevenbell](https://github.com/stevenbell)
 - Steven Williams [@onomou](https://github.com/onomou)
+- [@svanderwulp](https://github.com/svanderwulp)
 - Tinson Lai [@laitingsheng](https://github.com/laitingsheng)
 - Toan Vu [@vutoan1245](https://github.com/vutoan1245)
 - [@Tobiaqs](https://github.com/Tobiaqs)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 532f4cc..39d8e44 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,48 @@
 
 ## [Unreleased]
 
+## [3.1.0] - 2023-04-21
+
+### New Endpoint Coverage
+
+- Account Calendars (Thanks, [@dmols](https://github.com/dmols))
+    - List available account calendars
+    - Get a single account calendar
+    - Update a calendar's visibility
+    - Update many calendars' visibility
+    - List all account calendars
+- Enrollments (Thanks, [@svanderwulp](https://github.com/svanderwulp))
+    - Accept Course Invitation
+    - Reject Course Invitation
+- File (Thanks, [@bennettscience](https://github.com/bennettscience))
+    - Update File
+- JWTs (Thanks [@dmols](https://github.com/dmols))
+    - Create JWTs
+    - Refresh JWTs
+- Moderation Grading (Moderation Set)
+    - List students selected for moderation
+    - Select students for moderation
+- Query Course Events (Thanks, [@dmols](https://github.com/dmols))
+    - Query by course
+    - Query by account
+- Rubrics (Thanks, [@bennettscience](https://github.com/bennettscience))
+    - Create, Update, and Delete Rubric Assessments
+    - Create a Rubric Association
+- Users
+    - Terminate all user sessions (Thanks, [@lucas-salas](https://github.com/lucas-salas))
+
+### General
+
+- Updated Codecov action to v3
+
+### Bugfixes
+
+- Fixed an issue where kwargs were not passed along to Canvas in `Course.get_module()`. (Thanks, [@bennettscience](https://github.com/bennettscience))
+- Fixed an issue where not all functions allowed arbitrary keyword arguments. Added a test to detect and prevent this for the future.
+- Fixed an issue with `Course.get_enabled_features()` where it would throw an error trying to paginate. It now returns a list of strings directly. (Thanks, [@bennettscience](https://github.com/bennettscience))
+- Added missing docs for `AssignmentOverride`. (Thanks, [@lafent](https://github.com/lafent))
+- Fixed a typo in `Canvas.create_calendar_event()` where an error message improperly listed the missing key as 'context_codes' instead of 'context_code'. (Thanks, [@dmols](https://github.com/dmols) and [@mikesuhan](https://github.com/mikesuhan))
+
 ## [3.0.0] - 2022-09-21
 
 ### New Endpoint Coverage
@@ -563,7 +605,8 @@ Huge thanks to [@liblit](https://github.com/liblit) for lots of issues, suggesti
 - Fixed some incorrectly defined parameters
 - Fixed an issue where tests would fail due to an improperly configured requires block
 
-[Unreleased]: https://github.com/ucfopen/canvasapi/compare/v3.0.0...develop
+[Unreleased]: https://github.com/ucfopen/canvasapi/compare/v3.1.0...develop
+[3.1.0]: https://github.com/ucfopen/canvasapi/compare/v3.0.0...v3.1.0
 [3.0.0]: https://github.com/ucfopen/canvasapi/compare/v2.2.0...v3.0.0
 [2.2.0]: https://github.com/ucfopen/canvasapi/compare/v2.1.0...v2.2.0
 [2.1.0]: https://github.com/ucfopen/canvasapi/compare/v2.0.0...v2.1.0
diff --git a/canvasapi/__init__.py b/canvasapi/__init__.py
index 45b18f8..c3f2ed2 100644
--- a/canvasapi/__init__.py
+++ b/canvasapi/__init__.py
@@ -4,4 +4,4 @@ from canvasapi.canvas import Canvas
 
 __all__ = ["Canvas"]
 
-__version__ = "3.0.0"
+__version__ = "3.1.0"
diff --git a/canvasapi/account.py b/canvasapi/account.py
index 2aa37ee..a1c39c1 100644
--- a/canvasapi/account.py
+++ b/canvasapi/account.py
@@ -1,12 +1,26 @@
+from canvasapi.account_calendar import AccountCalendar
+from canvasapi.authentication_event import AuthenticationEvent
+from canvasapi.authentication_provider import AuthenticationProvider
 from canvasapi.canvas_object import CanvasObject
+from canvasapi.content_migration import ContentMigration, Migrator
+from canvasapi.course import Course
+from canvasapi.course_event import CourseEvent
+from canvasapi.enrollment import Enrollment
+from canvasapi.enrollment_term import EnrollmentTerm
 from canvasapi.exceptions import CanvasException, RequiredFieldMissing
+from canvasapi.external_tool import ExternalTool
 from canvasapi.feature import Feature, FeatureFlag
 from canvasapi.grading_period import GradingPeriod
 from canvasapi.grading_standard import GradingStandard
+from canvasapi.group import Group, GroupCategory
+from canvasapi.login import Login
+from canvasapi.outcome import OutcomeGroup, OutcomeLink
 from canvasapi.outcome_import import OutcomeImport
 from canvasapi.paginated_list import PaginatedList
 from canvasapi.rubric import Rubric
+from canvasapi.scope import Scope
 from canvasapi.sis_import import SisImport
+from canvasapi.user import User
 from canvasapi.util import combine_kwargs, file_or_path, obj_or_id, obj_or_str
 
 
@@ -62,8 +76,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.authentication_provider.AuthenticationProvider`
         """
-        from canvasapi.authentication_provider import AuthenticationProvider
-
         response = self._requester.request(
             "POST",
             "accounts/{}/authentication_providers".format(self.id),
@@ -123,8 +135,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.account.AccountNotification`
         """
-        from canvasapi.user import User
-
         user_id = obj_or_id(user, "user", (User,))
         notif_id = obj_or_id(notification, "notification", (AccountNotification,))
 
@@ -165,8 +175,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.account.Admin`
         """
-        from canvasapi.user import User
-
         user_id = obj_or_id(user, "user", (User,))
         kwargs["user_id"] = user_id
 
@@ -189,8 +197,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.content_migration.ContentMigration`
         """
-        from canvasapi.content_migration import ContentMigration, Migrator
-
         if isinstance(migration_type, Migrator):
             kwargs["migration_type"] = migration_type.type
         elif isinstance(migration_type, str):
@@ -218,8 +224,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.course.Course`
         """
-        from canvasapi.course import Course
-
         response = self._requester.request(
             "POST",
             "accounts/{}/courses".format(self.id),
@@ -237,8 +241,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.enrollment_term.EnrollmentTerm`
         """
-        from canvasapi.enrollment_term import EnrollmentTerm
-
         response = self._requester.request(
             "POST",
             "accounts/{}/terms".format(self.id),
@@ -269,8 +271,6 @@ class Account(CanvasObject):
         :type shared_secret: str
         :rtype: :class:`canvasapi.external_tool.ExternalTool`
         """
-        from canvasapi.external_tool import ExternalTool
-
         response = self._requester.request(
             "POST",
             "accounts/{}/external_tools".format(self.id),
@@ -296,8 +296,6 @@ class Account(CanvasObject):
         :type name: str
         :rtype: :class:`canvasapi.group.GroupCategory`
         """
-        from canvasapi.group import GroupCategory
-
         response = self._requester.request(
             "POST",
             "accounts/{}/group_categories".format(self.id),
@@ -326,10 +324,8 @@ class Account(CanvasObject):
             kwargs["account_notification"] = account_notification
         else:
             raise RequiredFieldMissing(
-                (
-                    "account_notification must be a dictionary with keys "
-                    "'subject', 'message', 'start_at', and 'end_at'."
-                )
+                "account_notification must be a dictionary with keys "
+                "'subject', 'message', 'start_at', and 'end_at'."
             )
 
         response = self._requester.request(
@@ -355,7 +351,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.account.AccountReport`
         """
-
         response = self._requester.request(
             "POST",
             "accounts/{}/reports/{}".format(self.id, report_type),
@@ -398,7 +393,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.sis_import.SisImport`
         """
-
         attachment, is_path = file_or_path(attachment)
 
         try:
@@ -452,8 +446,6 @@ class Account(CanvasObject):
         :type pseudonym: dict
         :rtype: :class:`canvasapi.user.User`
         """
-        from canvasapi.user import User
-
         if isinstance(pseudonym, dict) and "unique_id" in pseudonym:
             kwargs["pseudonym"] = pseudonym
         else:
@@ -479,18 +471,16 @@ class Account(CanvasObject):
         :type login: `dict`
         :rtype: :class:`canvasapi.login.Login`
         """
-        from canvasapi.login import Login
-
         if isinstance(user, dict) and "id" in user:
             kwargs["user"] = user
         else:
-            raise RequiredFieldMissing(("user must be a dictionary with keys " "'id'."))
+            raise RequiredFieldMissing("user must be a dictionary with keys 'id'.")
 
         if isinstance(login, dict) and "unique_id" in login:
             kwargs["login"] = login
         else:
             raise RequiredFieldMissing(
-                ("login must be a dictionary with keys " "'unique_id'.")
+                "login must be a dictionary with keys 'unique_id'."
             )
 
         response = self._requester.request(
@@ -557,8 +547,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.account.Admin`
         """
-        from canvasapi.user import User
-
         user_id = obj_or_id(user, "user", (User,))
         kwargs["user_id"] = user_id
 
@@ -616,8 +604,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.user.User`
         """
-        from canvasapi.user import User
-
         user_id = obj_or_id(user, "user", (User,))
 
         response = self._requester.request(
@@ -627,6 +613,24 @@ class Account(CanvasObject):
         )
         return User(self._requester, response.json())
 
+    def get_account_calendar(self, **kwargs):
+        """
+        Returns information about a single account calendar.
+
+        :calls: `GET /api/v1/account_calendars/:account_id \
+        <https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.show>`_
+
+        :rtype: :class:`canvasapi.account_calendar.AccountCalendar`
+        """
+
+        response = self._requester.request(
+            "GET",
+            "account_calendars/{}".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        return AccountCalendar(self._requester, response.json())
+
     def get_admins(self, **kwargs):
         """
         Get the paginated list of admins for the current account.
@@ -645,6 +649,25 @@ class Account(CanvasObject):
             _kwargs=combine_kwargs(**kwargs),
         )
 
+    def get_all_account_calendars(self, **kwargs):
+        """
+        Lists all account calendars available to the account given.
+
+        :calls: `GET /api/v1/accounts/:account_id/account_calendars \
+        <https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.all_calendars>`_
+
+        :returns: Paginated list of all account calendars for the provided account.
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.account_calendar.AccountCalendar`
+        """
+        return PaginatedList(
+            AccountCalendar,
+            self._requester,
+            "GET",
+            "accounts/{}/account_calendars".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def get_all_outcome_links_in_context(self, **kwargs):
         """
         Get all outcome links for context - BETA
@@ -656,8 +679,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.outcome.OutcomeLink`
         """
-        from canvasapi.outcome import OutcomeLink
-
         return PaginatedList(
             OutcomeLink,
             self._requester,
@@ -676,8 +697,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
                 :class:`canvasapi.authentication_event.AuthenticationEvent`
         """
-        from canvasapi.authentication_event import AuthenticationEvent
-
         return PaginatedList(
             AuthenticationEvent,
             self._requester,
@@ -699,8 +718,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.authentication_provider.AuthenticationProvider`
         """
-        from canvasapi.authentication_provider import AuthenticationProvider
-
         authentication_providers_id = obj_or_id(
             authentication_provider,
             "authentication provider",
@@ -727,8 +744,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.authentication_provider.AuthenticationProvider`
         """
-        from canvasapi.authentication_provider import AuthenticationProvider
-
         return PaginatedList(
             AuthenticationProvider,
             self._requester,
@@ -750,8 +765,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.content_migration.ContentMigration`
         """
-        from canvasapi.content_migration import ContentMigration
-
         migration_id = obj_or_id(
             content_migration, "content_migration", (ContentMigration,)
         )
@@ -777,8 +790,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.content_migration.ContentMigration`
         """
-        from canvasapi.content_migration import ContentMigration
-
         return PaginatedList(
             ContentMigration,
             self._requester,
@@ -798,8 +809,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.course.Course`
         """
-        from canvasapi.course import Course
-
         return PaginatedList(
             Course,
             self._requester,
@@ -817,7 +826,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/completed/grades".format(self.id),
@@ -834,7 +842,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/current/grades".format(self.id),
@@ -854,7 +861,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/terms/{}/grades".format(self.id, term_id),
@@ -871,7 +877,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/completed/activity".format(self.id),
@@ -888,7 +893,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/current/activity".format(self.id),
@@ -910,7 +914,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/terms/{}/activity".format(self.id, term_id),
@@ -927,7 +930,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/completed/statistics".format(self.id),
@@ -944,7 +946,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/current/statistics".format(self.id),
@@ -964,7 +965,6 @@ class Account(CanvasObject):
 
         :rtype: dict
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/analytics/terms/{}/statistics".format(self.id, term_id),
@@ -979,18 +979,16 @@ class Account(CanvasObject):
         :calls: `GET /api/v1/accounts/:account_id/features/enabled \
         <https://canvas.instructure.com/doc/api/feature_flags.html#method.feature_flags.enabled_features>`_
 
-        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
-            :class:`canvasapi.feature.Feature`
+        :rtype: `list` of `str`
         """
-        return PaginatedList(
-            Feature,
-            self._requester,
+        response = self._requester.request(
             "GET",
             "accounts/{}/features/enabled".format(self.id),
-            {"account_id": self.id},
             _kwargs=combine_kwargs(**kwargs),
         )
 
+        return response.json()
+
     def get_enrollment(self, enrollment, **kwargs):
         """
         Get an enrollment object by ID.
@@ -1003,8 +1001,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.enrollment.Enrollment`
         """
-        from canvasapi.enrollment import Enrollment
-
         enrollment_id = obj_or_id(enrollment, "enrollment", (Enrollment,))
 
         response = self._requester.request(
@@ -1026,8 +1022,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.enrollment_term.EnrollmentTerm`
         """
-        from canvasapi.enrollment_term import EnrollmentTerm
-
         term_id = obj_or_id(term, "term", (EnrollmentTerm,))
 
         response = self._requester.request(
@@ -1045,8 +1039,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.enrollment_term.EnrollmentTerm`
         """
-        from canvasapi.enrollment_term import EnrollmentTerm
-
         return PaginatedList(
             EnrollmentTerm,
             self._requester,
@@ -1067,8 +1059,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.external_tool.ExternalTool`
         """
-        from canvasapi.external_tool import ExternalTool
-
         tool_id = obj_or_id(tool, "tool", (ExternalTool,))
 
         response = self._requester.request(
@@ -1089,8 +1079,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.external_tool.ExternalTool`
         """
-        from canvasapi.external_tool import ExternalTool
-
         return PaginatedList(
             ExternalTool,
             self._requester,
@@ -1152,7 +1140,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.account.AccountNotification`
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/account_notifications/{}".format(self.id, notification_id),
@@ -1174,7 +1161,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.grading_period.GradingPeriod`
         """
-
         return PaginatedList(
             GradingPeriod,
             self._requester,
@@ -1195,7 +1181,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.grading_standards.GradingStandard`
         """
-
         return PaginatedList(
             GradingStandard,
             self._requester,
@@ -1214,8 +1199,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.group.GroupCategory`
         """
-        from canvasapi.group import GroupCategory
-
         return PaginatedList(
             GroupCategory,
             self._requester,
@@ -1233,8 +1216,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.group.Group`
         """
-        from canvasapi.group import Group
-
         return PaginatedList(
             Group,
             self._requester,
@@ -1274,8 +1255,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.content_migration.Migrator`
         """
-        from canvasapi.content_migration import Migrator
-
         return PaginatedList(
             Migrator,
             self._requester,
@@ -1298,8 +1277,6 @@ class Account(CanvasObject):
         :returns: An outcome group object.
         :rtype: :class:`canvasapi.outcome.OutcomeGroup`
         """
-        from canvasapi.outcome import OutcomeGroup
-
         outcome_group_id = obj_or_id(group, "outcome group", (OutcomeGroup,))
         response = self._requester.request(
             "GET",
@@ -1320,8 +1297,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.outcome.OutcomeGroups`
         """
-        from canvasapi.outcome import OutcomeGroup
-
         return PaginatedList(
             OutcomeGroup,
             self._requester,
@@ -1438,7 +1413,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.account.Role`
         """
-
         return PaginatedList(
             Role,
             self._requester,
@@ -1457,8 +1431,6 @@ class Account(CanvasObject):
         :returns: The OutcomeGroup of the context.
         :rtype: :class:`canvasapi.outcome.OutcomeGroup`
         """
-        from canvasapi.outcome import OutcomeGroup
-
         response = self._requester.request(
             "GET",
             "accounts/{}/root_outcome_group".format(self.id),
@@ -1512,8 +1484,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.scope.Scope`
         """
-        from canvasapi.scope import Scope
-
         return PaginatedList(
             Scope,
             self._requester,
@@ -1533,7 +1503,6 @@ class Account(CanvasObject):
         :type grading_standard_id: int
         :rtype: :class:`canvasapi.grading_standards.GradingStandard`
         """
-
         response = self._requester.request(
             "GET",
             "accounts/%s/grading_standards/%d" % (self.id, grading_standard_id),
@@ -1576,7 +1545,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.sis_import.SisImport`
         """
-
         return PaginatedList(
             SisImport,
             self._requester,
@@ -1597,7 +1565,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList`
             of :class:`canvasapi.sis_import.SisImport`
         """
-
         return PaginatedList(
             SisImport,
             self._requester,
@@ -1640,8 +1607,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.login.Login`
         """
-        from canvasapi.login import Login
-
         return PaginatedList(
             Login,
             self._requester,
@@ -1665,8 +1630,6 @@ class Account(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.account.AccountNotification`
         """
-        from canvasapi.user import User
-
         user_id = obj_or_id(user, "user", (User,))
 
         return PaginatedList(
@@ -1686,8 +1649,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.user.User`
         """
-        from canvasapi.user import User
-
         return PaginatedList(
             User,
             self._requester,
@@ -1708,7 +1669,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.outcome_import.OutcomeImport`
         """
-
         attachment, is_path = file_or_path(attachment)
 
         try:
@@ -1727,6 +1687,24 @@ class Account(CanvasObject):
             if is_path:
                 attachment.close()
 
+    def query_audit_by_account(self, **kwargs):
+        """
+        List course change events for a specific account.
+
+        :calls: `GET /api/v1/audit/course/accounts/:account_id \
+        <https://canvas.instructure.com/doc/api/course_audit_log.html#method.course_audit_api.for_account>`_
+
+        :rtype: list of :class:`canvasapi.course_event.CourseEvent`
+        """
+
+        return PaginatedList(
+            CourseEvent,
+            self._requester,
+            "GET",
+            "audit/course/accounts/{}".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def show_account_auth_settings(self, **kwargs):
         """
         Return the current state of each account level setting
@@ -1736,7 +1714,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.account.SSOSettings`
         """
-
         response = self._requester.request(
             "GET",
             "accounts/{}/sso_settings".format(self.id),
@@ -1774,7 +1751,6 @@ class Account(CanvasObject):
 
         :rtype: :class:`canvasapi.account.SSOSettings`
         """
-
         response = self._requester.request(
             "PUT",
             "accounts/{}/sso_settings".format(self.id),
@@ -1783,6 +1759,40 @@ class Account(CanvasObject):
 
         return SSOSettings(self._requester, response.json())
 
+    def update_account_calendar_visibility(self, **kwargs):
+        """
+        Update one account calendar's visibility.
+
+        :calls: `PUT /api/v1/account_calendars/:account_id \
+        <https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.update>`_
+
+        :rtype: :class:`canvasapi.account_calendar.AccountCalendar`
+        """
+        response = self._requester.request(
+            "PUT",
+            "account_calendars/{}".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        return AccountCalendar(self._requester, response.json())
+
+    def update_many_account_calendars_visibility(self, **kwargs):
+        """
+        Update many account calendars visibility at once.
+
+        :calls: `PUT /api/v1/accounts/:account_id/account_calendars \
+        <https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.bulk_update>`_
+
+        :rtype: :class:`canvasapi.account_calendar.AccountCalendar`
+        """
+        response = self._requester.request(
+            "PUT",
+            "accounts/{}/account_calendars".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        return AccountCalendar(self._requester, response.json())
+
     def update_role(self, role, **kwargs):
         """
         Update permissions for an existing role.
@@ -1830,10 +1840,8 @@ class AccountNotification(CanvasObject):
             kwargs["account_notification"] = account_notification
         else:
             raise RequiredFieldMissing(
-                (
-                    "account_notification must be a dictionary with keys "
-                    "'subject', 'message', 'start_at', and 'end_at'."
-                )
+                "account_notification must be a dictionary with keys "
+                "'subject', 'message', 'start_at', and 'end_at'."
             )
 
         response = self._requester.request(
diff --git a/canvasapi/account_calendar.py b/canvasapi/account_calendar.py
new file mode 100644
index 0000000..3ae3e53
--- /dev/null
+++ b/canvasapi/account_calendar.py
@@ -0,0 +1,6 @@
+from canvasapi.canvas_object import CanvasObject
+
+
+class AccountCalendar(CanvasObject):
+    def __str__(self):
+        return "{} {} ({})".format(self.name, self.visible, self.calendar_event_url)
diff --git a/canvasapi/appointment_group.py b/canvasapi/appointment_group.py
index 27a5d72..5091987 100644
--- a/canvasapi/appointment_group.py
+++ b/canvasapi/appointment_group.py
@@ -39,7 +39,7 @@ class AppointmentGroup(CanvasObject):
             kwargs["appointment_group"] = appointment_group
         else:
             raise RequiredFieldMissing(
-                "Dictionary with key 'context_codes' is required."
+                "Dictionary with key 'context_code' is required."
             )
 
         response = self._requester.request(
diff --git a/canvasapi/assignment.py b/canvasapi/assignment.py
index 325be72..c09a420 100644
--- a/canvasapi/assignment.py
+++ b/canvasapi/assignment.py
@@ -207,6 +207,26 @@ class Assignment(CanvasObject):
 
         return request_json.get("needs_provisional_grade")
 
+    def get_students_selected_for_moderation(self, **kwargs):
+        """
+        Get a list of students selected for moderation.
+
+        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/moderated_students \
+        <https://canvas.instructure.com/doc/api/moderated_grading.html#method.moderation_set.index>`_
+
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.user.User`
+        """
+        return PaginatedList(
+            User,
+            self._requester,
+            "GET",
+            "courses/{}/assignments/{}/moderated_students".format(
+                self.course_id, self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def get_submission(self, user, **kwargs):
         """
         Get a single submission, based on user id.
@@ -277,6 +297,27 @@ class Assignment(CanvasObject):
         )
         return response.json()
 
+    def select_students_for_moderation(self, **kwargs):
+        """
+        Select student(s) for moderation.
+
+        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/moderated_students \
+        <https://canvas.instructure.com/doc/api/moderated_grading.html#method.moderation_set.create>`_
+
+        :returns: The list of users that were selected
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.user.User`
+        """
+        return PaginatedList(
+            User,
+            self._requester,
+            "POST",
+            "courses/{}/assignments/{}/moderated_students".format(
+                self.course_id, self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def selected_provisional_grade(self, provisional_grade_id, **kwargs):
         """
         Choose which provisional grade the student should receive for a submission.
@@ -522,7 +563,7 @@ class AssignmentOverride(CanvasObject):
         """
         Delete this assignment override.
 
-        :calls: `DELETE /api/v1/courses/:course_id/assignments/:assignment_id/overrides/:id
+        :calls: `DELETE /api/v1/courses/:course_id/assignments/:assignment_id/overrides/:id \
         <https://canvas.instructure.com/doc/api/assignments.html#method.assignment_overrides.destroy>`_
 
         :returns: The previous content of the now-deleted assignment override.
@@ -547,7 +588,7 @@ class AssignmentOverride(CanvasObject):
 
         Note: All current overridden values must be supplied if they are to be retained.
 
-        :calls: `PUT /api/v1/courses/:course_id/assignments/:assignment_id/overrides/:id
+        :calls: `PUT /api/v1/courses/:course_id/assignments/:assignment_id/overrides/:id \
         <https://canvas.instructure.com/doc/api/assignments.html#method.assignment_overrides.update>`_
 
         :rtype: :class:`canvasapi.assignment.AssignmentOverride`
diff --git a/canvasapi/authentication_provider.py b/canvasapi/authentication_provider.py
index 5ffd5c3..f74a799 100644
--- a/canvasapi/authentication_provider.py
+++ b/canvasapi/authentication_provider.py
@@ -6,6 +6,22 @@ class AuthenticationProvider(CanvasObject):
     def __str__(self):  # pragma: no cover
         return "{} ({})".format(self.auth_type, self.position)
 
+    def delete(self, **kwargs):
+        """
+        Delete the config
+
+        :calls: `DELETE /api/v1/accounts/:account_id/authentication_providers/:id \
+        <https://canvas.instructure.com/doc/api/authentication_providers.html#method.account_authorization_configs.destroy>`_
+
+        :rtype: :class:`canvasapi.authentication_provider.AuthenticationProvider`
+        """
+        response = self._requester.request(
+            "DELETE",
+            "accounts/{}/authentication_providers/{}".format(self.account_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return AuthenticationProvider(self._requester, response.json())
+
     def update(self, **kwargs):
         """
         Update an authentication provider using the same options as the create endpoint
@@ -25,18 +41,3 @@ class AuthenticationProvider(CanvasObject):
             super(AuthenticationProvider, self).set_attributes(response.json())
 
         return response.json().get("auth_type")
-
-    def delete(self):
-        """
-        Delete the config
-
-        :calls: `DELETE /api/v1/accounts/:account_id/authentication_providers/:id \
-        <https://canvas.instructure.com/doc/api/authentication_providers.html#method.account_authorization_configs.destroy>`_
-
-        :rtype: :class:`canvasapi.authentication_provider.AuthenticationProvider`
-        """
-        response = self._requester.request(
-            "DELETE",
-            "accounts/{}/authentication_providers/{}".format(self.account_id, self.id),
-        )
-        return AuthenticationProvider(self._requester, response.json())
diff --git a/canvasapi/canvas.py b/canvasapi/canvas.py
index ede6194..aaa23e0 100644
--- a/canvasapi/canvas.py
+++ b/canvasapi/canvas.py
@@ -1,16 +1,26 @@
 import warnings
 
 from canvasapi.account import Account
+from canvasapi.account_calendar import AccountCalendar
+from canvasapi.appointment_group import AppointmentGroup
+from canvasapi.calendar_event import CalendarEvent
 from canvasapi.comm_message import CommMessage
-from canvasapi.course import Course
+from canvasapi.conversation import Conversation
+from canvasapi.course import Course, CourseNickname
 from canvasapi.course_epub_export import CourseEpubExport
 from canvasapi.current_user import CurrentUser
+from canvasapi.discussion_topic import DiscussionTopic
 from canvasapi.eportfolio import EPortfolio
 from canvasapi.exceptions import RequiredFieldMissing
 from canvasapi.file import File
 from canvasapi.folder import Folder
 from canvasapi.group import Group, GroupCategory
+from canvasapi.jwt import JWT
+from canvasapi.outcome import Outcome, OutcomeGroup
 from canvasapi.paginated_list import PaginatedList
+from canvasapi.planner import PlannerNote, PlannerOverride
+from canvasapi.poll import Poll
+from canvasapi.progress import Progress
 from canvasapi.requester import Requester
 from canvasapi.section import Section
 from canvasapi.todo import Todo
@@ -93,9 +103,6 @@ class Canvas(object):
         :type event: `str`
         :rtype: :class:`canvasapi.progress.Progress`
         """
-
-        from canvasapi.progress import Progress
-
         ALLOWED_EVENTS = [
             "mark_as_read",
             "mark_as_unread",
@@ -206,8 +213,6 @@ class Canvas(object):
         :type title: `str`
         :rtype: :class:`canvasapi.appointment_group.AppointmentGroup`
         """
-        from canvasapi.appointment_group import AppointmentGroup
-
         if (
             isinstance(appointment_group, dict)
             and "context_codes" in appointment_group
@@ -243,13 +248,11 @@ class Canvas(object):
         :type calendar_event: `dict`
         :rtype: :class:`canvasapi.calendar_event.CalendarEvent`
         """
-        from canvasapi.calendar_event import CalendarEvent
-
         if isinstance(calendar_event, dict) and "context_code" in calendar_event:
             kwargs["calendar_event"] = calendar_event
         else:
             raise RequiredFieldMissing(
-                "Dictionary with key 'context_codes' is required."
+                "Dictionary with key 'context_code' is required."
             )
 
         response = self.__requester.request(
@@ -274,8 +277,6 @@ class Canvas(object):
         :type body: `str`
         :rtype: list of :class:`canvasapi.conversation.Conversation`
         """
-        from canvasapi.conversation import Conversation
-
         kwargs["recipients"] = recipients
         kwargs["body"] = body
 
@@ -298,6 +299,21 @@ class Canvas(object):
         )
         return Group(self.__requester, response.json())
 
+    def create_jwt(self, **kwargs):
+        """
+        Creates a unique JWT to use with other Canvas services.
+
+        :calls: `POST /api/v1/jwts \
+        <https://canvas.instructure.com/doc/api/jw_ts.html#method.jwts.create>`_
+
+        :rtype: list of :class:`canvasapi.jwt.JWT`
+        """
+        response = self.__requester.request(
+            "POST", "jwts", _kwargs=combine_kwargs(**kwargs)
+        )
+
+        return JWT(self.__requester, response.json())
+
     def create_planner_note(self, **kwargs):
         """
         Create a planner note for the current user
@@ -307,8 +323,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.planner.PlannerNote`
         """
-        from canvasapi.planner import PlannerNote
-
         response = self.__requester.request(
             "POST", "planner_notes", _kwargs=combine_kwargs(**kwargs)
         )
@@ -329,8 +343,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.planner.PlannerOverride`
         """
-        from canvasapi.planner import PlannerOverride
-
         if isinstance(plannable_type, str):
             kwargs["plannable_type"] = plannable_type
         else:
@@ -356,8 +368,6 @@ class Canvas(object):
         :type polls: list of dict
         :rtype: :class:`canvasapi.poll.Poll`
         """
-        from canvasapi.poll import Poll
-
         if (
             isinstance(polls, list)
             and isinstance(polls[0], dict)
@@ -401,6 +411,24 @@ class Canvas(object):
         )
         return Account(self.__requester, response.json())
 
+    def get_account_calendars(self, **kwargs):
+        """
+        Returns a paginated list of account calendars available to the user.
+
+        :calls: `GET /api/v1/account_calendars \
+        <https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.index>`_
+
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.account_calendar.AccountCalendar`
+        """
+        return PaginatedList(
+            AccountCalendar,
+            self.__requester,
+            "GET",
+            "account_calendars",
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def get_accounts(self, **kwargs):
         """
         List accounts that the current user can view or manage.
@@ -452,8 +480,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
                 :class:`canvasapi.discussion_topic.DiscussionTopic`
         """
-        from canvasapi.discussion_topic import DiscussionTopic
-
         if type(context_codes) is not list or len(context_codes) == 0:
             raise RequiredFieldMissing("context_codes need to be passed as a list")
 
@@ -493,8 +519,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.appointment_group.AppointmentGroup`
         """
-        from canvasapi.appointment_group import AppointmentGroup
-
         appointment_group_id = obj_or_id(
             appointment_group, "appointment_group", (AppointmentGroup,)
         )
@@ -516,8 +540,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.appointment_group.AppointmentGroup`
         """
-        from canvasapi.appointment_group import AppointmentGroup
-
         return PaginatedList(
             AppointmentGroup,
             self.__requester,
@@ -553,8 +575,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.calendar_event.CalendarEvent`
         """
-        from canvasapi.calendar_event import CalendarEvent
-
         calendar_event_id = obj_or_id(
             calendar_event, "calendar_event", (CalendarEvent,)
         )
@@ -576,8 +596,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.calendar_event.CalendarEvent`
         """
-        from canvasapi.calendar_event import CalendarEvent
-
         return PaginatedList(
             CalendarEvent,
             self.__requester,
@@ -624,8 +642,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.conversation.Conversation`
         """
-        from canvasapi.conversation import Conversation
-
         conversation_id = obj_or_id(conversation, "conversation", (Conversation,))
 
         response = self.__requester.request(
@@ -645,8 +661,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of \
         :class:`canvasapi.conversation.Conversation`
         """
-        from canvasapi.conversation import Conversation
-
         return PaginatedList(
             Conversation,
             self.__requester,
@@ -716,8 +730,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.course.CourseNickname`
         """
-        from canvasapi.course import CourseNickname
-
         course_id = obj_or_id(course, "course", (Course,))
 
         response = self.__requester.request(
@@ -737,8 +749,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.course.CourseNickname`
         """
-        from canvasapi.course import CourseNickname
-
         return PaginatedList(
             CourseNickname,
             self.__requester,
@@ -914,9 +924,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.group.Group`
         """
-        from canvasapi.appointment_group import AppointmentGroup
-        from canvasapi.group import Group
-
         appointment_group_id = obj_or_id(
             appointment_group, "appointment_group", (AppointmentGroup,)
         )
@@ -942,8 +949,6 @@ class Canvas(object):
         :returns: An Outcome object.
         :rtype: :class:`canvasapi.outcome.Outcome`
         """
-        from canvasapi.outcome import Outcome
-
         outcome_id = obj_or_id(outcome, "outcome", (Outcome,))
         response = self.__requester.request(
             "GET", "outcomes/{}".format(outcome_id), _kwargs=combine_kwargs(**kwargs)
@@ -963,8 +968,6 @@ class Canvas(object):
         :returns: An outcome group object.
         :rtype: :class:`canvasapi.outcome.OutcomeGroup`
         """
-        from canvasapi.outcome import OutcomeGroup
-
         outcome_group_id = obj_or_id(group, "group", (OutcomeGroup,))
 
         response = self.__requester.request(
@@ -987,8 +990,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.planner.PlannerNote`
         """
-        from canvasapi.planner import PlannerNote
-
         if isinstance(planner_note, int) or isinstance(planner_note, PlannerNote):
             planner_note_id = obj_or_id(planner_note, "planner_note", (PlannerNote,))
         else:
@@ -1014,8 +1015,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.planner.PlannerNote`
         """
-        from canvasapi.planner import PlannerNote
-
         return PaginatedList(
             PlannerNote,
             self.__requester,
@@ -1036,8 +1035,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.planner.PlannerOverride`
         """
-        from canvasapi.planner import PlannerOverride
-
         if isinstance(planner_override, int) or isinstance(
             planner_override, PlannerOverride
         ):
@@ -1067,8 +1064,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.planner.PlannerOverride`
         """
-        from canvasapi.planner import PlannerOverride
-
         return PaginatedList(
             PlannerOverride,
             self.__requester,
@@ -1088,8 +1083,6 @@ class Canvas(object):
         :type poll: int
         :rtype: :class:`canvasapi.poll.Poll`
         """
-        from canvasapi.poll import Poll
-
         poll_id = obj_or_id(poll, "poll", (Poll,))
 
         response = self.__requester.request(
@@ -1107,8 +1100,6 @@ class Canvas(object):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.poll.Poll`
         """
-        from canvasapi.poll import Poll
-
         return PaginatedList(
             Poll,
             self.__requester,
@@ -1130,9 +1121,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.progress.Progress`
         """
-
-        from canvasapi.progress import Progress
-
         progress_id = obj_or_id(progress, "progress", (Progress,))
 
         response = self.__requester.request(
@@ -1150,8 +1138,6 @@ class Canvas(object):
         :returns: The OutcomeGroup of the context.
         :rtype: :class:`canvasapi.outcome.OutcomeGroup`
         """
-        from canvasapi.outcome import OutcomeGroup
-
         response = self.__requester.request(
             "GET", "global/root_outcome_group", _kwargs=combine_kwargs(**kwargs)
         )
@@ -1260,9 +1246,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.user.User`
         """
-        from canvasapi.appointment_group import AppointmentGroup
-        from canvasapi.user import User
-
         appointment_group_id = obj_or_id(
             appointment_group, "appointment_group", (AppointmentGroup,)
         )
@@ -1302,6 +1285,27 @@ class Canvas(object):
 
         return response.json()
 
+    def refresh_jwt(self, jwt, **kwargs):
+        """
+        Refreshes a JWT for reuse with other canvas services. It generates a
+        different JWT each time it's called; expires after one hour.
+
+        :calls: `POST /api/v1/jwts/refresh \
+        <https://canvas.instructure.com/doc/api/jw_ts.html#method.jwts.refresh>`_
+
+        :param jwt: An existing JWT to refresh.
+        :type jwt: str or :class:`canvasapi.jwt.JWT`
+        :rtype: :class:`canvasapi.jwt.JWT`
+        """
+        if isinstance(jwt, JWT):
+            jwt = jwt.token
+
+        response = self.__requester.request(
+            "POST", "jwts/refresh", jwt=jwt, _kwargs=combine_kwargs(**kwargs)
+        )
+
+        return JWT(self.__requester, response.json())
+
     def reserve_time_slot(self, calendar_event, participant_id=None, **kwargs):
         """
         Return single Calendar Event by id
@@ -1317,8 +1321,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.calendar_event.CalendarEvent`
         """
-        from canvasapi.calendar_event import CalendarEvent
-
         calendar_event_id = obj_or_id(
             calendar_event, "calendar_event", (CalendarEvent,)
         )
@@ -1400,8 +1402,6 @@ class Canvas(object):
 
         :rtype: :class:`canvasapi.course.CourseNickname`
         """
-        from canvasapi.course import CourseNickname
-
         course_id = obj_or_id(course, "course", (Course,))
 
         kwargs["nickname"] = nickname
diff --git a/canvasapi/communication_channel.py b/canvasapi/communication_channel.py
index 9197537..acc8610 100644
--- a/canvasapi/communication_channel.py
+++ b/canvasapi/communication_channel.py
@@ -109,7 +109,6 @@ class CommunicationChannel(CanvasObject):
         :rtype: :class:`canvasapi.notification_preference.NotificationPreference`
         """
         if isinstance(notification_preferences, dict) and notification_preferences:
-
             for key, value in notification_preferences.items():
                 try:
                     if not value["frequency"]:
diff --git a/canvasapi/conversation.py b/canvasapi/conversation.py
index d1714b4..bb59f7d 100644
--- a/canvasapi/conversation.py
+++ b/canvasapi/conversation.py
@@ -6,43 +6,27 @@ class Conversation(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.subject, self.id)
 
-    def edit(self, **kwargs):
+    def add_message(self, body, **kwargs):
         """
-        Update a conversation.
+        Add a message to a conversation.
 
-        :calls: `PUT /api/v1/conversations/:id \
-        <https://canvas.instructure.com/doc/api/conversations.html#method.conversations.update>`_
+        :calls: `POST /api/v1/conversations/:id/add_message \
+        <https://canvas.instructure.com/doc/api/conversations.html#method.conversations.add_message>`_
 
-        :rtype: `bool`
+        :param body: The body of the conversation.
+        :type body: str
+        :returns: A conversation with only the most recent message.
+        :rtype: :class:`canvasapi.account.Conversation`
         """
         response = self._requester.request(
-            "PUT", "conversations/{}".format(self.id), _kwargs=combine_kwargs(**kwargs)
+            "POST",
+            "conversations/{}/add_message".format(self.id),
+            body=body,
+            _kwargs=combine_kwargs(**kwargs),
         )
+        return Conversation(self._requester, response.json())
 
-        if response.json().get("id"):
-            super(Conversation, self).set_attributes(response.json())
-            return True
-        else:
-            return False
-
-    def delete(self):
-        """
-        Delete a conversation.
-
-        :calls: `DELETE /api/v1/conversations/:id \
-        <https://canvas.instructure.com/doc/api/conversations.html#method.conversations.destroy>`_
-
-        :rtype: `bool`
-        """
-        response = self._requester.request("DELETE", "conversations/{}".format(self.id))
-
-        if response.json().get("id"):
-            super(Conversation, self).set_attributes(response.json())
-            return True
-        else:
-            return False
-
-    def add_recipients(self, recipients):
+    def add_recipients(self, recipients, **kwargs):
         """
         Add a recipient to a conversation.
 
@@ -60,30 +44,32 @@ class Conversation(CanvasObject):
             "POST",
             "conversations/{}/add_recipients".format(self.id),
             recipients=recipients,
+            _kwargs=combine_kwargs(**kwargs),
         )
         return Conversation(self._requester, response.json())
 
-    def add_message(self, body, **kwargs):
+    def delete(self, **kwargs):
         """
-        Add a message to a conversation.
+        Delete a conversation.
 
-        :calls: `POST /api/v1/conversations/:id/add_message \
-        <https://canvas.instructure.com/doc/api/conversations.html#method.conversations.add_message>`_
+        :calls: `DELETE /api/v1/conversations/:id \
+        <https://canvas.instructure.com/doc/api/conversations.html#method.conversations.destroy>`_
 
-        :param body: The body of the conversation.
-        :type body: str
-        :returns: A conversation with only the most recent message.
-        :rtype: :class:`canvasapi.account.Conversation`
+        :rtype: `bool`
         """
         response = self._requester.request(
-            "POST",
-            "conversations/{}/add_message".format(self.id),
-            body=body,
+            "DELETE",
+            "conversations/{}".format(self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
-        return Conversation(self._requester, response.json())
 
-    def delete_messages(self, remove):
+        if response.json().get("id"):
+            super(Conversation, self).set_attributes(response.json())
+            return True
+        else:
+            return False
+
+    def delete_messages(self, remove, **kwargs):
         """
         Delete messages from this conversation.
 
@@ -98,6 +84,28 @@ class Conversation(CanvasObject):
         :rtype: `dict`
         """
         response = self._requester.request(
-            "POST", "conversations/{}/remove_messages".format(self.id), remove=remove
+            "POST",
+            "conversations/{}/remove_messages".format(self.id),
+            remove=remove,
+            _kwargs=combine_kwargs(**kwargs),
         )
         return response.json()
+
+    def edit(self, **kwargs):
+        """
+        Update a conversation.
+
+        :calls: `PUT /api/v1/conversations/:id \
+        <https://canvas.instructure.com/doc/api/conversations.html#method.conversations.update>`_
+
+        :rtype: `bool`
+        """
+        response = self._requester.request(
+            "PUT", "conversations/{}".format(self.id), _kwargs=combine_kwargs(**kwargs)
+        )
+
+        if response.json().get("id"):
+            super(Conversation, self).set_attributes(response.json())
+            return True
+        else:
+            return False
diff --git a/canvasapi/course.py b/canvasapi/course.py
index 04351e0..0c3e227 100644
--- a/canvasapi/course.py
+++ b/canvasapi/course.py
@@ -4,10 +4,13 @@ from canvasapi.assignment import Assignment, AssignmentGroup
 from canvasapi.blueprint import BlueprintSubscription
 from canvasapi.canvas_object import CanvasObject
 from canvasapi.collaboration import Collaboration
+from canvasapi.content_export import ContentExport
 from canvasapi.course_epub_export import CourseEpubExport
+from canvasapi.course_event import CourseEvent
 from canvasapi.custom_gradebook_columns import CustomGradebookColumn
 from canvasapi.discussion_topic import DiscussionTopic
 from canvasapi.exceptions import RequiredFieldMissing
+from canvasapi.external_feed import ExternalFeed
 from canvasapi.feature import Feature, FeatureFlag
 from canvasapi.folder import Folder
 from canvasapi.grade_change_log import GradeChangeEvent
@@ -20,6 +23,7 @@ from canvasapi.gradebook_history import (
 from canvasapi.grading_period import GradingPeriod
 from canvasapi.grading_standard import GradingStandard
 from canvasapi.license import License
+from canvasapi.module import Module
 from canvasapi.outcome_import import OutcomeImport
 from canvasapi.page import Page
 from canvasapi.paginated_list import PaginatedList
@@ -322,8 +326,6 @@ class Course(CanvasObject):
         :type url: str
         :rtype: :class:`canvasapi.external_feed.ExternalFeed`
         """
-        from canvasapi.external_feed import ExternalFeed
-
         response = self._requester.request(
             "POST",
             "courses/{}/external_feeds".format(self.id),
@@ -435,8 +437,6 @@ class Course(CanvasObject):
         :returns: The created module.
         :rtype: :class:`canvasapi.module.Module`
         """
-        from canvasapi.module import Module
-
         if isinstance(module, dict) and "name" in module:
             kwargs["module"] = module
         else:
@@ -596,8 +596,6 @@ class Course(CanvasObject):
 
         :rtype: :class:`canvasapi.external_feed.ExternalFeed`
         """
-        from canvasapi.external_feed import ExternalFeed
-
         feed_id = obj_or_id(feed, "feed", (ExternalFeed,))
 
         response = self._requester.request(
@@ -695,8 +693,6 @@ class Course(CanvasObject):
 
         :rtype: :class:`canvasapi.content_export.ContentExport`
         """
-        from canvasapi.content_export import ContentExport
-
         kwargs["export_type"] = export_type
 
         response = self._requester.request(
@@ -927,8 +923,6 @@ class Course(CanvasObject):
 
         :rtype: :class:`canvasapi.content_export.ContentExport`
         """
-        from canvasapi.content_export import ContentExport
-
         export_id = obj_or_id(content_export, "content_export", (ContentExport,))
 
         response = self._requester.request(
@@ -949,8 +943,6 @@ class Course(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.content_export.ContentExport`
         """
-        from canvasapi.content_export import ContentExport
-
         return PaginatedList(
             ContentExport,
             self._requester,
@@ -1135,18 +1127,16 @@ class Course(CanvasObject):
         :calls: `GET /api/v1/courses/:course_id/features/enabled \
         <https://canvas.instructure.com/doc/api/feature_flags.html#method.feature_flags.enabled_features>`_
 
-        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
-            :class:`canvasapi.feature.Feature`
+        :rtype: `list` of `str`
         """
-        return PaginatedList(
-            Feature,
-            self._requester,
+        response = self._requester.request(
             "GET",
             "courses/{}/features/enabled".format(self.id),
-            {"course_id": self.id},
             _kwargs=combine_kwargs(**kwargs),
         )
 
+        return response.json()
+
     def get_enrollments(self, **kwargs):
         """
         List all of the enrollments in this course.
@@ -1200,8 +1190,6 @@ class Course(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.external_feed.ExternalFeed`
         """
-        from canvasapi.external_feed import ExternalFeed
-
         return PaginatedList(
             ExternalFeed,
             self._requester,
@@ -1653,13 +1641,14 @@ class Course(CanvasObject):
 
         :rtype: :class:`canvasapi.module.Module`
         """
-        from canvasapi.module import Module
-
         module_id = obj_or_id(module, "module", (Module,))
 
         response = self._requester.request(
-            "GET", "courses/{}/modules/{}".format(self.id, module_id)
+            "GET",
+            "courses/{}/modules/{}".format(self.id, module_id),
+            _kwargs=combine_kwargs(**kwargs),
         )
+
         module_json = response.json()
         module_json.update({"course_id": self.id})
 
@@ -1675,8 +1664,6 @@ class Course(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.module.Module`
         """
-        from canvasapi.module import Module
-
         return PaginatedList(
             Module,
             self._requester,
@@ -2382,6 +2369,24 @@ class Course(CanvasObject):
         )
         return response.json().get("html", "")
 
+    def query_audit_by_course(self, **kwargs):
+        """
+        Lists course change events for a specific course.
+
+        :calls: `GET /api/v1/audit/course/courses/:course_id \
+        <https://canvas.instructure.com/doc/api/course_audit_log.html#method.course_audit_api.for_course>`_
+
+        :rtype: list of :class:`canvasapi.course_event.CourseEvent`
+        """
+
+        return PaginatedList(
+            CourseEvent,
+            self._requester,
+            "GET",
+            "audit/course/courses/{}".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
     def remove_usage_rights(self, **kwargs):
         """
         Removes the usage rights for specified files that are under the current course scope
diff --git a/canvasapi/course_event.py b/canvasapi/course_event.py
new file mode 100644
index 0000000..344cbd1
--- /dev/null
+++ b/canvasapi/course_event.py
@@ -0,0 +1,6 @@
+from canvasapi.canvas_object import CanvasObject
+
+
+class CourseEvent(CanvasObject):
+    def __str__(self):
+        return "{} {} ({})".format(self.name, self.start_at, self.conclude_at)
diff --git a/canvasapi/enrollment.py b/canvasapi/enrollment.py
index 476c8f7..bd4ab84 100644
--- a/canvasapi/enrollment.py
+++ b/canvasapi/enrollment.py
@@ -6,6 +6,23 @@ class Enrollment(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.type, self.id)
 
+    def accept(self, **kwargs):
+        """
+        Accept a pending course invitation.
+
+        :calls: `POST /api/v1/courses/:course_id/enrollments/:id/accept \
+        <https://canvas.instructure.com/doc/api/enrollments.html#method.enrollments_api.accept>`_
+
+        :returns: True if the course invitation was accepted.
+        :rtype: bool
+        """
+        response = self._requester.request(
+            "POST",
+            "courses/{}/enrollments/{}/accept".format(self.course_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return response.json().get("success", False)
+
     def deactivate(self, task, **kwargs):
         """
         Delete, conclude, or deactivate an enrollment.
@@ -53,3 +70,20 @@ class Enrollment(CanvasObject):
             _kwargs=combine_kwargs(**kwargs),
         )
         return Enrollment(self._requester, response.json())
+
+    def reject(self, **kwargs):
+        """
+        Reject a pending course invitation.
+
+        :calls: `POST /api/v1/courses/:course_id/enrollments/:id/reject \
+        <https://canvas.instructure.com/doc/api/enrollments.html#method.enrollments_api.reject>`_
+
+        :returns: True if the course invitation was rejected.
+        :rtype: bool
+        """
+        response = self._requester.request(
+            "POST",
+            "courses/{}/enrollments/{}/reject".format(self.course_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return response.json().get("success", False)
diff --git a/canvasapi/enrollment_term.py b/canvasapi/enrollment_term.py
index a2a4d14..8de88e8 100644
--- a/canvasapi/enrollment_term.py
+++ b/canvasapi/enrollment_term.py
@@ -6,7 +6,7 @@ class EnrollmentTerm(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.name, self.id)
 
-    def delete(self):
+    def delete(self, **kwargs):
         """
         Delete this Enrollment Term.
 
@@ -16,7 +16,9 @@ class EnrollmentTerm(CanvasObject):
         :rtype: :class:`canvasapi.enrollment_term.EnrollmentTerm`
         """
         response = self._requester.request(
-            "DELETE", "accounts/{}/terms/{}".format(self.account_id, self.id)
+            "DELETE",
+            "accounts/{}/terms/{}".format(self.account_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
         )
         return EnrollmentTerm(self._requester, response.json())
 
diff --git a/canvasapi/external_tool.py b/canvasapi/external_tool.py
index 41d5616..9d8afa2 100644
--- a/canvasapi/external_tool.py
+++ b/canvasapi/external_tool.py
@@ -35,25 +35,7 @@ class ExternalTool(CanvasObject):
         else:
             raise ValueError("ExternalTool does not have a course_id or account_id")
 
-    def get_parent(self):
-        """
-        Return the object that spawned this tool.
-
-        :rtype: :class:`canvasapi.account.Account` or :class:`canvasapi.account.Course`
-        """
-        from canvasapi.account import Account
-        from canvasapi.course import Course
-
-        response = self._requester.request(
-            "GET", "{}s/{}".format(self.parent_type, self.parent_id)
-        )
-
-        if self.parent_type == "account":
-            return Account(self._requester, response.json())
-        elif self.parent_type == "course":
-            return Course(self._requester, response.json())
-
-    def delete(self):
+    def delete(self, **kwargs):
         """
         Remove the specified external tool.
 
@@ -69,6 +51,7 @@ class ExternalTool(CanvasObject):
             "{}s/{}/external_tools/{}".format(
                 self.parent_type, self.parent_id, self.id
             ),
+            _kwargs=combine_kwargs(**kwargs),
         )
 
         return ExternalTool(self._requester, response.json())
@@ -98,6 +81,26 @@ class ExternalTool(CanvasObject):
 
         return ExternalTool(self._requester, response_json)
 
+    def get_parent(self, **kwargs):
+        """
+        Return the object that spawned this tool.
+
+        :rtype: :class:`canvasapi.account.Account` or :class:`canvasapi.account.Course`
+        """
+        from canvasapi.account import Account
+        from canvasapi.course import Course
+
+        response = self._requester.request(
+            "GET",
+            "{}s/{}".format(self.parent_type, self.parent_id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        if self.parent_type == "account":
+            return Account(self._requester, response.json())
+        elif self.parent_type == "course":
+            return Course(self._requester, response.json())
+
     def get_sessionless_launch_url(self, **kwargs):
         """
         Return a sessionless launch url for an external tool.
diff --git a/canvasapi/file.py b/canvasapi/file.py
index 81439f6..e4acbf3 100644
--- a/canvasapi/file.py
+++ b/canvasapi/file.py
@@ -44,3 +44,17 @@ class File(CanvasObject):
             return response.content
         else:
             return response.text
+
+    def update(self, **kwargs):
+        """
+        Update some settings on the specified file.
+
+        :calls: `PUT /api/v1/files/:id \
+        <https://canvas.instructure.com/doc/api/files.html#method.files.api_update>`_
+
+        :rtype: :class:`canvasapi.file.File`
+        """
+        response = self._requester.request(
+            "PUT", "files/{}".format(self.id), _kwargs=combine_kwargs(**kwargs)
+        )
+        return File(self._requester, response.json())
diff --git a/canvasapi/group.py b/canvasapi/group.py
index 1acb666..b9aaad4 100644
--- a/canvasapi/group.py
+++ b/canvasapi/group.py
@@ -2,6 +2,7 @@ from canvasapi.canvas_object import CanvasObject
 from canvasapi.collaboration import Collaboration
 from canvasapi.discussion_topic import DiscussionTopic
 from canvasapi.exceptions import RequiredFieldMissing
+from canvasapi.external_feed import ExternalFeed
 from canvasapi.folder import Folder
 from canvasapi.license import License
 from canvasapi.paginated_list import PaginatedList
@@ -78,8 +79,6 @@ class Group(CanvasObject):
         :type url: str
         :rtype: :class:`canvasapi.external_feed.ExternalFeed`
         """
-        from canvasapi.external_feed import ExternalFeed
-
         response = self._requester.request(
             "POST",
             "groups/{}/external_feeds".format(self.id),
diff --git a/canvasapi/jwt.py b/canvasapi/jwt.py
new file mode 100644
index 0000000..72988fd
--- /dev/null
+++ b/canvasapi/jwt.py
@@ -0,0 +1,6 @@
+from canvasapi.canvas_object import CanvasObject
+
+
+class JWT(CanvasObject):
+    def __str__(self):
+        return "{}".format(self.token)
diff --git a/canvasapi/login.py b/canvasapi/login.py
index e24f844..5089e9b 100644
--- a/canvasapi/login.py
+++ b/canvasapi/login.py
@@ -7,7 +7,7 @@ class Login(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.id, self.unique_id)
 
-    def delete(self):
+    def delete(self, **kwargs):
         """
         Delete an existing login.
 
@@ -17,7 +17,9 @@ class Login(CanvasObject):
         :rtype: :class:`canvasapi.login.Login`
         """
         response = self._requester.request(
-            "DELETE", "users/{}/logins/{}".format(self.user_id, self.id)
+            "DELETE",
+            "users/{}/logins/{}".format(self.user_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
         )
         return Login(self._requester, response.json())
 
diff --git a/canvasapi/module.py b/canvasapi/module.py
index fe6b3b2..4403af4 100644
--- a/canvasapi/module.py
+++ b/canvasapi/module.py
@@ -8,26 +8,43 @@ class Module(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.name, self.id)
 
-    def edit(self, **kwargs):
+    def create_module_item(self, module_item, **kwargs):
         """
-        Update this module.
+        Create a module item.
 
-        :calls: `PUT /api/v1/courses/:course_id/modules/:id \
-        <https://canvas.instructure.com/doc/api/modules.html#method.context_modules_api.update>`_
+        :calls: `POST /api/v1/courses/:course_id/modules/:module_id/items \
+        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.create>`_
 
-        :rtype: :class:`canvasapi.module.Module`
+        :param module_item: The attributes to create the module item with.
+        :type module_item: dict
+        :returns: The created module item.
+        :rtype: :class:`canvasapi.module.ModuleItem`
         """
+
+        unrequired_types = ["ExternalUrl", "Page", "SubHeader"]
+
+        if isinstance(module_item, dict) and "type" in module_item:
+            # content_id is not required for unrequired_types
+            if module_item["type"] in unrequired_types or "content_id" in module_item:
+                kwargs["module_item"] = module_item
+            else:
+                raise RequiredFieldMissing(
+                    "Dictionary with key 'content_id' is required."
+                )
+        else:
+            raise RequiredFieldMissing("Dictionary with key 'type' is required.")
+
         response = self._requester.request(
-            "PUT",
-            "courses/{}/modules/{}".format(self.course_id, self.id),
+            "POST",
+            "courses/{}/modules/{}/items".format(self.course_id, self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
-        module_json = response.json()
-        module_json.update({"course_id": self.course_id})
+        module_item_json = response.json()
+        module_item_json.update({"course_id": self.course_id})
 
-        return Module(self._requester, module_json)
+        return ModuleItem(self._requester, module_item_json)
 
-    def delete(self):
+    def delete(self, **kwargs):
         """
         Delete this module.
 
@@ -37,53 +54,34 @@ class Module(CanvasObject):
         :rtype: :class:`canvasapi.module.Module`
         """
         response = self._requester.request(
-            "DELETE", "courses/{}/modules/{}".format(self.course_id, self.id)
+            "DELETE",
+            "courses/{}/modules/{}".format(self.course_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
         )
         module_json = response.json()
         module_json.update({"course_id": self.course_id})
 
         return Module(self._requester, module_json)
 
-    def relock(self):
+    def edit(self, **kwargs):
         """
-        Reset module progressions to their default locked state and recalculates
-        them based on the current requirements.
-
-        Adding progression requirements to an active course will not lock students
-        out of modules they have already unlocked unless this action is called.
+        Update this module.
 
-        :calls: `PUT /api/v1/courses/:course_id/modules/:id/relock \
-        <https://canvas.instructure.com/doc/api/modules.html#method.context_modules_api.relock>`_
+        :calls: `PUT /api/v1/courses/:course_id/modules/:id \
+        <https://canvas.instructure.com/doc/api/modules.html#method.context_modules_api.update>`_
 
         :rtype: :class:`canvasapi.module.Module`
         """
         response = self._requester.request(
-            "PUT", "courses/{}/modules/{}/relock".format(self.course_id, self.id)
+            "PUT",
+            "courses/{}/modules/{}".format(self.course_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
         )
         module_json = response.json()
         module_json.update({"course_id": self.course_id})
 
         return Module(self._requester, module_json)
 
-    def get_module_items(self, **kwargs):
-        """
-        List all of the items in this module.
-
-        :calls: `GET /api/v1/courses/:course_id/modules/:module_id/items \
-        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.index>`_
-
-        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
-            :class:`canvasapi.module.ModuleItem`
-        """
-        return PaginatedList(
-            ModuleItem,
-            self._requester,
-            "GET",
-            "courses/{}/modules/{}/items".format(self.course_id, self.id),
-            {"course_id": self.course_id},
-            _kwargs=combine_kwargs(**kwargs),
-        )
-
     def get_module_item(self, module_item, **kwargs):
         """
         Retrieve a module item by ID.
@@ -110,60 +108,65 @@ class Module(CanvasObject):
 
         return ModuleItem(self._requester, module_item_json)
 
-    def create_module_item(self, module_item, **kwargs):
+    def get_module_items(self, **kwargs):
         """
-        Create a module item.
+        List all of the items in this module.
 
-        :calls: `POST /api/v1/courses/:course_id/modules/:module_id/items \
-        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.create>`_
+        :calls: `GET /api/v1/courses/:course_id/modules/:module_id/items \
+        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.index>`_
 
-        :param module_item: The attributes to create the module item with.
-        :type module_item: dict
-        :returns: The created module item.
-        :rtype: :class:`canvasapi.module.ModuleItem`
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.module.ModuleItem`
         """
+        return PaginatedList(
+            ModuleItem,
+            self._requester,
+            "GET",
+            "courses/{}/modules/{}/items".format(self.course_id, self.id),
+            {"course_id": self.course_id},
+            _kwargs=combine_kwargs(**kwargs),
+        )
 
-        unrequired_types = ["ExternalUrl", "Page", "SubHeader"]
+    def relock(self, **kwargs):
+        """
+        Reset module progressions to their default locked state and recalculates
+        them based on the current requirements.
 
-        if isinstance(module_item, dict) and "type" in module_item:
-            # content_id is not required for unrequired_types
-            if module_item["type"] in unrequired_types or "content_id" in module_item:
-                kwargs["module_item"] = module_item
-            else:
-                raise RequiredFieldMissing(
-                    "Dictionary with key 'content_id' is required."
-                )
-        else:
-            raise RequiredFieldMissing("Dictionary with key 'type' is required.")
+        Adding progression requirements to an active course will not lock students
+        out of modules they have already unlocked unless this action is called.
 
+        :calls: `PUT /api/v1/courses/:course_id/modules/:id/relock \
+        <https://canvas.instructure.com/doc/api/modules.html#method.context_modules_api.relock>`_
+
+        :rtype: :class:`canvasapi.module.Module`
+        """
         response = self._requester.request(
-            "POST",
-            "courses/{}/modules/{}/items".format(self.course_id, self.id),
+            "PUT",
+            "courses/{}/modules/{}/relock".format(self.course_id, self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
-        module_item_json = response.json()
-        module_item_json.update({"course_id": self.course_id})
+        module_json = response.json()
+        module_json.update({"course_id": self.course_id})
 
-        return ModuleItem(self._requester, module_item_json)
+        return Module(self._requester, module_json)
 
 
 class ModuleItem(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.title, self.id)
 
-    def edit(self, **kwargs):
+    def complete(self, **kwargs):
         """
-        Update this module item.
+        Mark this module item as done.
 
-        :calls: `PUT /api/v1/courses/:course_id/modules/:module_id/items/:id \
-        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.update>`_
+        :calls: `PUT /api/v1/courses/:course_id/modules/:module_id/items/:id/done \
+        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.mark_as_done>`_
 
-        :returns: The updated module item.
         :rtype: :class:`canvasapi.module.ModuleItem`
         """
         response = self._requester.request(
             "PUT",
-            "courses/{}/modules/{}/items/{}".format(
+            "courses/{}/modules/{}/items/{}/done".format(
                 self.course_id, self.module_id, self.id
             ),
             _kwargs=combine_kwargs(**kwargs),
@@ -173,7 +176,7 @@ class ModuleItem(CanvasObject):
 
         return ModuleItem(self._requester, module_item_json)
 
-    def delete(self):
+    def delete(self, **kwargs):
         """
         Delete this module item.
 
@@ -187,33 +190,36 @@ class ModuleItem(CanvasObject):
             "courses/{}/modules/{}/items/{}".format(
                 self.course_id, self.module_id, self.id
             ),
+            _kwargs=combine_kwargs(**kwargs),
         )
         module_item_json = response.json()
         module_item_json.update({"course_id": self.course_id})
 
         return ModuleItem(self._requester, module_item_json)
 
-    def complete(self):
+    def edit(self, **kwargs):
         """
-        Mark this module item as done.
+        Update this module item.
 
-        :calls: `PUT /api/v1/courses/:course_id/modules/:module_id/items/:id/done \
-        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.mark_as_done>`_
+        :calls: `PUT /api/v1/courses/:course_id/modules/:module_id/items/:id \
+        <https://canvas.instructure.com/doc/api/modules.html#method.context_module_items_api.update>`_
 
+        :returns: The updated module item.
         :rtype: :class:`canvasapi.module.ModuleItem`
         """
         response = self._requester.request(
             "PUT",
-            "courses/{}/modules/{}/items/{}/done".format(
+            "courses/{}/modules/{}/items/{}".format(
                 self.course_id, self.module_id, self.id
             ),
+            _kwargs=combine_kwargs(**kwargs),
         )
         module_item_json = response.json()
         module_item_json.update({"course_id": self.course_id})
 
         return ModuleItem(self._requester, module_item_json)
 
-    def uncomplete(self):
+    def uncomplete(self, **kwargs):
         """
         Mark this module item as not done.
 
@@ -227,6 +233,7 @@ class ModuleItem(CanvasObject):
             "courses/{}/modules/{}/items/{}/done".format(
                 self.course_id, self.module_id, self.id
             ),
+            _kwargs=combine_kwargs(**kwargs),
         )
         module_item_json = response.json()
         module_item_json.update({"course_id": self.course_id})
diff --git a/canvasapi/outcome.py b/canvasapi/outcome.py
index 9adf291..4baa955 100644
--- a/canvasapi/outcome.py
+++ b/canvasapi/outcome.py
@@ -39,7 +39,7 @@ class OutcomeLink(CanvasObject):
         elif self.context_type == "Account":
             return "accounts/{}".format(self.context_id)
 
-    def get_outcome(self):
+    def get_outcome(self, **kwargs):
         """
         Return the linked outcome
 
@@ -50,11 +50,13 @@ class OutcomeLink(CanvasObject):
         :rtype: :class:`canvasapi.outcome.Outcome`
         """
         oid = self.outcome["id"]
-        response = self._requester.request("GET", "outcomes/{}".format(oid))
+        response = self._requester.request(
+            "GET", "outcomes/{}".format(oid), _kwargs=combine_kwargs(**kwargs)
+        )
 
         return Outcome(self._requester, response.json())
 
-    def get_outcome_group(self):
+    def get_outcome_group(self, **kwargs):
         """
         Return the linked outcome group
 
@@ -70,7 +72,9 @@ class OutcomeLink(CanvasObject):
         """
         ogid = self.outcome_group["id"]
         response = self._requester.request(
-            "GET", "{}/outcome_groups/{}".format(self.context_ref(), ogid)
+            "GET",
+            "{}/outcome_groups/{}".format(self.context_ref(), ogid),
+            _kwargs=combine_kwargs(**kwargs),
         )
 
         return OutcomeGroup(self._requester, response.json())
@@ -88,32 +92,33 @@ class OutcomeGroup(CanvasObject):
         elif self.context_type is None:
             return "global"
 
-    def update(self, **kwargs):
+    def create_subgroup(self, title, **kwargs):
         """
-        Update an outcome group.
+        Create a subgroup of the current group
 
-        :calls: `PUT /api/v1/global/outcome_groups/:id \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.update>`_
-            or `PUT /api/v1/accounts/:account_id/outcome_groups/:id \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.update>`_
-            or `PUT /api/v1/courses/:course_id/outcome_groups/:id \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.update>`_
+        :calls: `POST /api/v1/global/outcome_groups/:id/subgroups \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.create>`_
+            or `POST /api/v1/accounts/:account_id/outcome_groups/:id/subgroups \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.create>`_
+            or `POST /api/v1/courses/:course_id/outcome_groups/:id/subgroups \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.create>`_
 
-        :returns: True if updated, False otherwise.
-        :rtype: bool
+        :param title: The title of the subgroup.
+        :type title: str
+
+        :returns: Itself as an OutcomeGroup object.
+        :rtype: :class:`canvasapi.outcome.OutcomeGroup`
         """
         response = self._requester.request(
-            "PUT",
-            "{}/outcome_groups/{}".format(self.context_ref(), self.id),
+            "POST",
+            "{}/outcome_groups/{}/subgroups".format(self.context_ref(), self.id),
+            title=title,
             _kwargs=combine_kwargs(**kwargs),
         )
 
-        if "id" in response.json():
-            super(OutcomeGroup, self).set_attributes(response.json())
-
-        return "id" in response.json()
+        return OutcomeGroup(self._requester, response.json())
 
-    def delete(self):
+    def delete(self, **kwargs):
         """
         Delete an outcome group.
 
@@ -128,7 +133,9 @@ class OutcomeGroup(CanvasObject):
         :rtype: bool
         """
         response = self._requester.request(
-            "DELETE", "{}/outcome_groups/{}".format(self.context_ref(), self.id)
+            "DELETE",
+            "{}/outcome_groups/{}".format(self.context_ref(), self.id),
+            _kwargs=combine_kwargs(**kwargs),
         )
 
         if "id" in response.json():
@@ -159,7 +166,61 @@ class OutcomeGroup(CanvasObject):
             _kwargs=combine_kwargs(**kwargs),
         )
 
-    def link_existing(self, outcome):
+    def get_subgroups(self, **kwargs):
+        """
+        List subgroups.
+
+        :calls: `GET /api/v1/global/outcome_groups/:id/subgroups \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.subgroups>`_
+            or `GET /api/v1/accounts/:account_id/outcome_groups/:id/subgroups \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.subgroups>`_
+            or `GET /api/v1/courses/:course_id/outcome_groups/:id/subgroups \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.subgroups>`_
+
+        :returns: Paginated List of OutcomeGroups linked to the current group.
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.outcome.OutcomeGroup`
+        """
+        return PaginatedList(
+            OutcomeGroup,
+            self._requester,
+            "GET",
+            "{}/outcome_groups/{}/subgroups".format(self.context_ref(), self.id),
+            {"context_type": self.context_type, "context_id": self.context_id},
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+    def import_outcome_group(self, outcome_group, **kwargs):
+        """
+        Import an outcome group as a subgroup into the current outcome group
+
+        :calls: `POST /api/v1/global/outcome_groups/:id/import \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.import>`_
+            or `POST /api/v1/accounts/:account_id/outcome_groups/:id/import \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.import>`_
+            or `POST /api/v1/courses/:course_id/outcome_groups/:id/import \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.import>`_
+
+        :param outcome: The object or ID of the outcome group to import.
+        :type outcome: :class:`canvasapi.outcome.OutcomeGroup` or int
+
+        :returns: Itself as an OutcomeGroup object.
+        :rtype: :class:`canvasapi.outcome.OutcomeGroup`
+        """
+        source_outcome_group_id = obj_or_id(
+            outcome_group, "outcome_group", (OutcomeGroup,)
+        )
+
+        response = self._requester.request(
+            "POST",
+            "{}/outcome_groups/{}/import".format(self.context_ref(), self.id),
+            source_outcome_group_id=source_outcome_group_id,
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        return OutcomeGroup(self._requester, response.json())
+
+    def link_existing(self, outcome, **kwargs):
         """
         Link to an existing Outcome.
 
@@ -181,8 +242,11 @@ class OutcomeGroup(CanvasObject):
         response = self._requester.request(
             "PUT",
             "{}/outcome_groups/{}/outcomes/{}".format(
-                self.context_ref(), self.id, outcome_id
+                self.context_ref(),
+                self.id,
+                outcome_id,
             ),
+            _kwargs=combine_kwargs(**kwargs),
         )
 
         return OutcomeLink(self._requester, response.json())
@@ -213,7 +277,7 @@ class OutcomeGroup(CanvasObject):
 
         return OutcomeLink(self._requester, response.json())
 
-    def unlink_outcome(self, outcome):
+    def unlink_outcome(self, outcome, **kwargs):
         """
         Remove an Outcome from and OutcomeLink
 
@@ -235,8 +299,11 @@ class OutcomeGroup(CanvasObject):
         response = self._requester.request(
             "DELETE",
             "{}/outcome_groups/{}/outcomes/{}".format(
-                self.context_ref(), self.id, outcome_id
+                self.context_ref(),
+                self.id,
+                outcome_id,
             ),
+            _kwargs=combine_kwargs(**kwargs),
         )
 
         if "context_id" in response.json():
@@ -244,84 +311,30 @@ class OutcomeGroup(CanvasObject):
 
         return "context_id" in response.json()
 
-    def get_subgroups(self, **kwargs):
-        """
-        List subgroups.
-
-        :calls: `GET /api/v1/global/outcome_groups/:id/subgroups \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.subgroups>`_
-            or `GET /api/v1/accounts/:account_id/outcome_groups/:id/subgroups \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.subgroups>`_
-            or `GET /api/v1/courses/:course_id/outcome_groups/:id/subgroups \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.subgroups>`_
-
-        :returns: Paginated List of OutcomeGroups linked to the current group.
-        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
-            :class:`canvasapi.outcome.OutcomeGroup`
-        """
-        return PaginatedList(
-            OutcomeGroup,
-            self._requester,
-            "GET",
-            "{}/outcome_groups/{}/subgroups".format(self.context_ref(), self.id),
-            {"context_type": self.context_type, "context_id": self.context_id},
-            _kwargs=combine_kwargs(**kwargs),
-        )
-
-    def create_subgroup(self, title, **kwargs):
+    def update(self, **kwargs):
         """
-        Create a subgroup of the current group
-
-        :calls: `POST /api/v1/global/outcome_groups/:id/subgroups \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.create>`_
-            or `POST /api/v1/accounts/:account_id/outcome_groups/:id/subgroups \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.create>`_
-            or `POST /api/v1/courses/:course_id/outcome_groups/:id/subgroups \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.create>`_
+        Update an outcome group.
 
-        :param title: The title of the subgroup.
-        :type title: str
+        :calls: `PUT /api/v1/global/outcome_groups/:id \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.update>`_
+            or `PUT /api/v1/accounts/:account_id/outcome_groups/:id \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.update>`_
+            or `PUT /api/v1/courses/:course_id/outcome_groups/:id \
+            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.update>`_
 
-        :returns: Itself as an OutcomeGroup object.
-        :rtype: :class:`canvasapi.outcome.OutcomeGroup`
+        :returns: True if updated, False otherwise.
+        :rtype: bool
         """
         response = self._requester.request(
-            "POST",
-            "{}/outcome_groups/{}/subgroups".format(self.context_ref(), self.id),
-            title=title,
+            "PUT",
+            "{}/outcome_groups/{}".format(self.context_ref(), self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
 
-        return OutcomeGroup(self._requester, response.json())
-
-    def import_outcome_group(self, outcome_group):
-        """
-        Import an outcome group as a subgroup into the current outcome group
-
-        :calls: `POST /api/v1/global/outcome_groups/:id/import \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.import>`_
-            or `POST /api/v1/accounts/:account_id/outcome_groups/:id/import \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.import>`_
-            or `POST /api/v1/courses/:course_id/outcome_groups/:id/import \
-            <https://canvas.instructure.com/doc/api/outcome_groups.html#method.outcome_groups_api.import>`_
-
-        :param outcome: The object or ID of the outcome group to import.
-        :type outcome: :class:`canvasapi.outcome.OutcomeGroup` or int
-
-        :returns: Itself as an OutcomeGroup object.
-        :rtype: :class:`canvasapi.outcome.OutcomeGroup`
-        """
-        source_outcome_group_id = obj_or_id(
-            outcome_group, "outcome_group", (OutcomeGroup,)
-        )
-
-        response = self._requester.request(
-            "POST",
-            "{}/outcome_groups/{}/import".format(self.context_ref(), self.id),
-            source_outcome_group_id=source_outcome_group_id,
-        )
+        if "id" in response.json():
+            super(OutcomeGroup, self).set_attributes(response.json())
 
-        return OutcomeGroup(self._requester, response.json())
+        return "id" in response.json()
 
 
 class OutcomeResult(CanvasObject):
diff --git a/canvasapi/paginated_list.py b/canvasapi/paginated_list.py
index 9be9fc3..ce14420 100644
--- a/canvasapi/paginated_list.py
+++ b/canvasapi/paginated_list.py
@@ -27,7 +27,6 @@ class PaginatedList(object):
         _root=None,
         **kwargs
     ):
-
         self._elements = list()
 
         self._requester = requester
diff --git a/canvasapi/planner.py b/canvasapi/planner.py
index 32946af..a4b688e 100644
--- a/canvasapi/planner.py
+++ b/canvasapi/planner.py
@@ -6,36 +6,36 @@ class PlannerNote(CanvasObject):
     def __str__(self):
         return "{} {} ({})".format(self.title, self.todo_date, self.id)
 
-    def update(self, **kwargs):
+    def delete(self, **kwargs):
         """
-        Update a planner note for the current user
+        Delete a planner note for the current user
 
-        :calls: `PUT /api/v1/planner_notes/:id \
-        <https://canvas.instructure.com/doc/api/planner.html#method.planner_notes.update>`_
+        :calls: `DELETE /api/v1/planner_notes/:id \
+        <https://canvas.instructure.com/doc/api/planner.html#method.planner_notes.destroy>`_
 
         :rtype: :class:`canvasapi.planner.PlannerNote`
         """
-
         response = self._requester.request(
-            "PUT", "planner_notes/{}".format(self.id), _kwargs=combine_kwargs(**kwargs)
+            "DELETE",
+            "planner_notes/{}".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
         )
+
         return PlannerNote(self._requester, response.json())
 
-    def delete(self, **kwargs):
+    def update(self, **kwargs):
         """
-        Delete a planner note for the current user
+        Update a planner note for the current user
 
-        :calls: `DELETE /api/v1/planner_notes/:id \
-        <https://canvas.instructure.com/doc/api/planner.html#method.planner_notes.destroy>`_
+        :calls: `PUT /api/v1/planner_notes/:id \
+        <https://canvas.instructure.com/doc/api/planner.html#method.planner_notes.update>`_
 
         :rtype: :class:`canvasapi.planner.PlannerNote`
         """
+
         response = self._requester.request(
-            "DELETE",
-            "planner_notes/{}".format(self.id),
-            _kwargs=combine_kwargs(**kwargs),
+            "PUT", "planner_notes/{}".format(self.id), _kwargs=combine_kwargs(**kwargs)
         )
-
         return PlannerNote(self._requester, response.json())
 
 
@@ -43,36 +43,36 @@ class PlannerOverride(CanvasObject):
     def __str__(self):
         return "{} {} ({})".format(self.plannable_id, self.marked_complete, self.id)
 
-    def update(self, **kwargs):
+    def delete(self, **kwargs):
         """
-        Update a planner override's visibilty for the current user
+        Delete a planner override for the current user
 
-        :calls: `PUT /api/v1/planner/overrides/:id \
-        <https://canvas.instructure.com/doc/api/planner.html#method.planner_overrides.update>`_
+        :calls: `DELETE /api/v1/planner/overrides/:id \
+        <https://canvas.instructure.com/doc/api/planner.html#method.planner_overrides.destroy>`_
 
         :rtype: :class:`canvasapi.planner.PlannerOverride`
         """
-
         response = self._requester.request(
-            "PUT",
+            "DELETE",
             "planner/overrides/{}".format(self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
+
         return PlannerOverride(self._requester, response.json())
 
-    def delete(self, **kwargs):
+    def update(self, **kwargs):
         """
-        Delete a planner override for the current user
+        Update a planner override's visibilty for the current user
 
-        :calls: `DELETE /api/v1/planner/overrides/:id \
-        <https://canvas.instructure.com/doc/api/planner.html#method.planner_overrides.destroy>`_
+        :calls: `PUT /api/v1/planner/overrides/:id \
+        <https://canvas.instructure.com/doc/api/planner.html#method.planner_overrides.update>`_
 
         :rtype: :class:`canvasapi.planner.PlannerOverride`
         """
+
         response = self._requester.request(
-            "DELETE",
+            "PUT",
             "planner/overrides/{}".format(self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
-
         return PlannerOverride(self._requester, response.json())
diff --git a/canvasapi/poll.py b/canvasapi/poll.py
index da36574..622ef3f 100644
--- a/canvasapi/poll.py
+++ b/canvasapi/poll.py
@@ -10,30 +10,62 @@ class Poll(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.question, self.id)
 
-    def update(self, poll, **kwargs):
+    def create_choice(self, poll_choice, **kwargs):
         """
-        Update an existing poll belonging to the current user.
+        Create a new choice for the current poll.
 
-        :calls: `PUT /api/v1/polls/:id \
-        <https://canvas.instructure.com/doc/api/polls.html#method.polling/polls.update>`_
+        :calls: `POST /api/v1/polls/:poll_id/poll_choices \
+        <https://canvas.instructure.com/doc/api/poll_choices.html#method.polling/poll_choices.create>`_
 
-        :param poll: List of arguments. 'Question' is required and 'Description' is optional
-        :type poll: list
-        :rtype: :class:`canvasapi.poll.Poll`
+        :param poll_choice: 'text' is required, 'is_correct' and 'position' are optional.
+        :type poll_choice: list
+        :rtype: :class:`canvasapi.poll_choice.PollChoice`
         """
         if (
-            isinstance(poll, list)
-            and isinstance(poll[0], dict)
-            and "question" in poll[0]
+            isinstance(poll_choice, list)
+            and isinstance(poll_choice[0], dict)
+            and "text" in poll_choice[0]
         ):
-            kwargs["poll"] = poll
+            kwargs["poll_choice"] = poll_choice
         else:
-            raise RequiredFieldMissing("Dictionary with key 'question' is required.")
+            raise RequiredFieldMissing("Dictionary with key 'text' is required.")
 
         response = self._requester.request(
-            "PUT", "polls/{}".format(self.id), _kwargs=combine_kwargs(**kwargs)
+            "POST",
+            "polls/{}/poll_choices".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
         )
-        return Poll(self._requester, response.json()["polls"][0])
+        return PollChoice(self._requester, response.json()["poll_choices"][0])
+
+    def create_session(self, poll_session, **kwargs):
+        """
+        Create a new poll session for this poll
+
+        :calls: `POST /api/v1/polls/:poll_id/poll_sessions \
+        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.create>`_
+
+        :param poll_session: List of arguments. course_id (required): id of the course for the
+            session, course_section_id (optional): id of the course section for this session,
+            has_public_results (optional): whether the results are viewable by students.
+        :type poll_session: list
+
+        :rtype: :class:`canvasapi.poll_session.PollSession`
+        """
+        if (
+            isinstance(poll_session, list)
+            and isinstance(poll_session[0], dict)
+            and "course_id" in poll_session[0]
+        ):
+            kwargs["poll_session"] = poll_session
+        else:
+            raise RequiredFieldMissing("Dictionary with key 'course_id' is required.")
+
+        response = self._requester.request(
+            "POST",
+            "polls/{}/poll_sessions".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return PollSession(self._requester, response.json()["poll_sessions"][0])
 
     def delete(self, **kwargs):
         """
@@ -51,25 +83,6 @@ class Poll(CanvasObject):
         )
         return response.status_code == 204
 
-    def get_choices(self, **kwargs):
-        """
-        Returns a paginated list of PollChoices of a poll, based on poll id.
-
-        :calls: `GET /api/v1/polls/:poll_id/poll_choices \
-        <https://canvas.instructure.com/doc/api/poll_choices.html#method.polling/poll_choices.index>`_
-
-        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
-            :class:`canvasapi.poll_choice.PollChoice`
-        """
-        return PaginatedList(
-            PollChoice,
-            self._requester,
-            "GET",
-            "polls/{}/poll_choices".format(self.id),
-            _root="poll_choices",
-            _kwargs=combine_kwargs(**kwargs),
-        )
-
     def get_choice(self, poll_choice, **kwargs):
         """
         Returns the poll choice with the given id.
@@ -88,49 +101,22 @@ class Poll(CanvasObject):
         )
         return PollChoice(self._requester, response.json()["poll_choices"][0])
 
-    def create_choice(self, poll_choice, **kwargs):
-        """
-        Create a new choice for the current poll.
-
-        :calls: `POST /api/v1/polls/:poll_id/poll_choices \
-        <https://canvas.instructure.com/doc/api/poll_choices.html#method.polling/poll_choices.create>`_
-
-        :param poll_choice: 'text' is required, 'is_correct' and 'position' are optional.
-        :type poll_choice: list
-        :rtype: :class:`canvasapi.poll_choice.PollChoice`
-        """
-        if (
-            isinstance(poll_choice, list)
-            and isinstance(poll_choice[0], dict)
-            and "text" in poll_choice[0]
-        ):
-            kwargs["poll_choice"] = poll_choice
-        else:
-            raise RequiredFieldMissing("Dictionary with key 'text' is required.")
-
-        response = self._requester.request(
-            "POST",
-            "polls/{}/poll_choices".format(self.id),
-            _kwargs=combine_kwargs(**kwargs),
-        )
-        return PollChoice(self._requester, response.json()["poll_choices"][0])
-
-    def get_sessions(self, **kwargs):
+    def get_choices(self, **kwargs):
         """
-        Returns the paginated list of PollSessions in a poll.
+        Returns a paginated list of PollChoices of a poll, based on poll id.
 
-        :calls: `GET /api/v1/polls/:poll_id/poll_sessions \
-        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.index>`_
+        :calls: `GET /api/v1/polls/:poll_id/poll_choices \
+        <https://canvas.instructure.com/doc/api/poll_choices.html#method.polling/poll_choices.index>`_
 
-        :rtype: :class:`canvasapi.paginated_lsit.Paginated List` of
-            :class:`canvasapi.poll_session.PollSession`
+        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
+            :class:`canvasapi.poll_choice.PollChoice`
         """
         return PaginatedList(
-            PollSession,
+            PollChoice,
             self._requester,
             "GET",
-            "polls/{}/poll_sessions".format(self.id),
-            _root="poll_sessions",
+            "polls/{}/poll_choices".format(self.id),
+            _root="poll_choices",
             _kwargs=combine_kwargs(**kwargs),
         )
 
@@ -155,32 +141,46 @@ class Poll(CanvasObject):
         )
         return PollSession(self._requester, response.json()["poll_sessions"][0])
 
-    def create_session(self, poll_session, **kwargs):
+    def get_sessions(self, **kwargs):
         """
-        Create a new poll session for this poll
+        Returns the paginated list of PollSessions in a poll.
 
-        :calls: `POST /api/v1/polls/:poll_id/poll_sessions \
-        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.create>`_
+        :calls: `GET /api/v1/polls/:poll_id/poll_sessions \
+        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.index>`_
 
-        :param poll_session: List of arguments. course_id (required): id of the course for the
-            session, course_section_id (optional): id of the course section for this session,
-            has_public_results (optional): whether the results are viewable by students.
-        :type poll_session: list
+        :rtype: :class:`canvasapi.paginated_lsit.Paginated List` of
+            :class:`canvasapi.poll_session.PollSession`
+        """
+        return PaginatedList(
+            PollSession,
+            self._requester,
+            "GET",
+            "polls/{}/poll_sessions".format(self.id),
+            _root="poll_sessions",
+            _kwargs=combine_kwargs(**kwargs),
+        )
 
-        :rtype: :class:`canvasapi.poll_session.PollSession`
+    def update(self, poll, **kwargs):
+        """
+        Update an existing poll belonging to the current user.
+
+        :calls: `PUT /api/v1/polls/:id \
+        <https://canvas.instructure.com/doc/api/polls.html#method.polling/polls.update>`_
+
+        :param poll: List of arguments. 'Question' is required and 'Description' is optional
+        :type poll: list
+        :rtype: :class:`canvasapi.poll.Poll`
         """
         if (
-            isinstance(poll_session, list)
-            and isinstance(poll_session[0], dict)
-            and "course_id" in poll_session[0]
+            isinstance(poll, list)
+            and isinstance(poll[0], dict)
+            and "question" in poll[0]
         ):
-            kwargs["poll_session"] = poll_session
+            kwargs["poll"] = poll
         else:
-            raise RequiredFieldMissing("Dictionary with key 'course_id' is required.")
+            raise RequiredFieldMissing("Dictionary with key 'question' is required.")
 
         response = self._requester.request(
-            "POST",
-            "polls/{}/poll_sessions".format(self.id),
-            _kwargs=combine_kwargs(**kwargs),
+            "PUT", "polls/{}".format(self.id), _kwargs=combine_kwargs(**kwargs)
         )
-        return PollSession(self._requester, response.json()["poll_sessions"][0])
+        return Poll(self._requester, response.json()["polls"][0])
diff --git a/canvasapi/poll_choice.py b/canvasapi/poll_choice.py
index ccf64df..90985d1 100644
--- a/canvasapi/poll_choice.py
+++ b/canvasapi/poll_choice.py
@@ -7,6 +7,24 @@ class PollChoice(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.text, self.id)
 
+    def delete(self, **kwargs):
+        """
+        Delete a single poll, based on the poll id.
+
+        :calls: `DELETE /api/v1/polls/:poll_id/poll_choices/:id \
+        <https://canvas.instructure.com/doc/api/poll_choices.html#method.polling/poll_choices.destroy>`_
+
+        :returns: True if the deletion was successful, false otherwise.
+
+        :rtype: bool
+        """
+        response = self._requester.request(
+            "DELETE",
+            "polls/{}/poll_choices/{}".format(self.poll_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return response.status_code == 204
+
     def update(self, poll_choice, **kwargs):
         """
         Update an existing choice for this poll.
@@ -34,21 +52,3 @@ class PollChoice(CanvasObject):
             _kwargs=combine_kwargs(**kwargs),
         )
         return PollChoice(self._requester, response.json()["poll_choices"][0])
-
-    def delete(self, **kwargs):
-        """
-        Delete a single poll, based on the poll id.
-
-        :calls: `DELETE /api/v1/polls/:poll_id/poll_choices/:id \
-        <https://canvas.instructure.com/doc/api/poll_choices.html#method.polling/poll_choices.destroy>`_
-
-        :returns: True if the deletion was successful, false otherwise.
-
-        :rtype: bool
-        """
-        response = self._requester.request(
-            "DELETE",
-            "polls/{}/poll_choices/{}".format(self.poll_id, self.id),
-            _kwargs=combine_kwargs(**kwargs),
-        )
-        return response.status_code == 204
diff --git a/canvasapi/poll_session.py b/canvasapi/poll_session.py
index e03b435..718497f 100644
--- a/canvasapi/poll_session.py
+++ b/canvasapi/poll_session.py
@@ -8,35 +8,52 @@ class PollSession(CanvasObject):
     def __str__(self):
         return "{} ({})".format(self.poll_id, self.id)
 
-    def update(self, poll_session, **kwargs):
+    def close(self, **kwargs):
         """
-        Update an existing poll session for a poll based on poll id.
+        Close a poll session to answers based on the poll id.
 
-        :calls: `PUT /api/v1/polls/:poll_id/poll_sessions/:id \
-        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.update>`_
+        :calls: `GET /api/v1/polls/:poll_id/poll_sessions/:id/close \
+        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.close>`_
 
-        :param poll_session: List of arguments. course_id (required): id of the course for the
-            session, course_section_id (optional): id of the course section for this session,
-            has_public_results (optional): whether the results are viewable by students.
-        :type poll_session: list
+        :returns: :class:`canvasapi.poll_session.PollSession`
+        """
+        response = self._requester.request(
+            "GET",
+            "polls/{}/poll_sessions/{}/close".format(self.poll_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return PollSession(self._requester, response.json()["poll_sessions"][0])
 
-        :rtype: :class:`canvasapi.poll_session.PollSession`
+    def create_submission(self, poll_submissions, **kwargs):
+        """
+        Create a new poll submission for this poll session.
+
+        :calls: `POST /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions \
+        <https://canvas.instructure.com/doc/api/poll_submissions.html#method.polling/poll_submissions.create>`_
+
+        :param poll_submissions: List of arguments. poll_choice_id (required int): Chosen poll \
+        choice for this submission.
+        :type poll_submissions: list
+
+        :rtype: :class:`canvasapi.poll_submission.PollSubmission`
         """
         if (
-            isinstance(poll_session, list)
-            and isinstance(poll_session[0], dict)
-            and "course_id" in poll_session[0]
+            isinstance(poll_submissions, list)
+            and isinstance(poll_submissions[0], dict)
+            and "poll_choice_id" in poll_submissions[0]
         ):
-            kwargs["poll_session"] = poll_session
+            kwargs["poll_submissions"] = poll_submissions
         else:
-            raise RequiredFieldMissing("Dictionary with key 'course_id' is required.")
+            raise RequiredFieldMissing(
+                "Dictionary with key 'poll_choice_id is required."
+            )
 
         response = self._requester.request(
-            "PUT",
-            "polls/{}/poll_sessions/{}".format(self.poll_id, self.id),
+            "POST",
+            "polls/{}/poll_sessions/{}/poll_submissions".format(self.poll_id, self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
-        return PollSession(self._requester, response.json()["poll_sessions"][0])
+        return PollSubmission(self._requester, response.json()["poll_submissions"][0])
 
     def delete(self, **kwargs):
         """
@@ -56,38 +73,6 @@ class PollSession(CanvasObject):
         )
         return response.status_code == 204
 
-    def open(self, **kwargs):
-        """
-        Open a poll session to answers based on the poll id.
-
-        :calls: `GET /api/v1/polls/:poll_id/poll_sessions/:id/open \
-        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.open>`_
-
-        :returns: :class:`canvasapi.poll_session.PollSession`
-        """
-        response = self._requester.request(
-            "GET",
-            "polls/{}/poll_sessions/{}/open".format(self.poll_id, self.id),
-            _kwargs=combine_kwargs(**kwargs),
-        )
-        return PollSession(self._requester, response.json()["poll_sessions"][0])
-
-    def close(self, **kwargs):
-        """
-        Close a poll session to answers based on the poll id.
-
-        :calls: `GET /api/v1/polls/:poll_id/poll_sessions/:id/close \
-        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.close>`_
-
-        :returns: :class:`canvasapi.poll_session.PollSession`
-        """
-        response = self._requester.request(
-            "GET",
-            "polls/{}/poll_sessions/{}/close".format(self.poll_id, self.id),
-            _kwargs=combine_kwargs(**kwargs),
-        )
-        return PollSession(self._requester, response.json()["poll_sessions"][0])
-
     def get_submission(self, poll_submission, **kwargs):
         """
         Returns the poll submission with the given id.
@@ -113,33 +98,48 @@ class PollSession(CanvasObject):
         )
         return PollSubmission(self._requester, response.json()["poll_submissions"][0])
 
-    def create_submission(self, poll_submissions, **kwargs):
+    def open(self, **kwargs):
         """
-        Create a new poll submission for this poll session.
+        Open a poll session to answers based on the poll id.
 
-        :calls: `POST /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions \
-        <https://canvas.instructure.com/doc/api/poll_submissions.html#method.polling/poll_submissions.create>`_
+        :calls: `GET /api/v1/polls/:poll_id/poll_sessions/:id/open \
+        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.open>`_
 
-        :param poll_submissions: List of arguments. poll_choice_id (required int): Chosen poll \
-        choice for this submission.
-        :type poll_submissions: list
+        :returns: :class:`canvasapi.poll_session.PollSession`
+        """
+        response = self._requester.request(
+            "GET",
+            "polls/{}/poll_sessions/{}/open".format(self.poll_id, self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return PollSession(self._requester, response.json()["poll_sessions"][0])
 
-        :rtype: :class:`canvasapi.poll_submission.PollSubmission`
+    def update(self, poll_session, **kwargs):
+        """
+        Update an existing poll session for a poll based on poll id.
+
+        :calls: `PUT /api/v1/polls/:poll_id/poll_sessions/:id \
+        <https://canvas.instructure.com/doc/api/poll_sessions.html#method.polling/poll_sessions.update>`_
+
+        :param poll_session: List of arguments. course_id (required): id of the course for the
+            session, course_section_id (optional): id of the course section for this session,
+            has_public_results (optional): whether the results are viewable by students.
+        :type poll_session: list
+
+        :rtype: :class:`canvasapi.poll_session.PollSession`
         """
         if (
-            isinstance(poll_submissions, list)
-            and isinstance(poll_submissions[0], dict)
-            and "poll_choice_id" in poll_submissions[0]
+            isinstance(poll_session, list)
+            and isinstance(poll_session[0], dict)
+            and "course_id" in poll_session[0]
         ):
-            kwargs["poll_submissions"] = poll_submissions
+            kwargs["poll_session"] = poll_session
         else:
-            raise RequiredFieldMissing(
-                "Dictionary with key 'poll_choice_id is required."
-            )
+            raise RequiredFieldMissing("Dictionary with key 'course_id' is required.")
 
         response = self._requester.request(
-            "POST",
-            "polls/{}/poll_sessions/{}/poll_submissions".format(self.poll_id, self.id),
+            "PUT",
+            "polls/{}/poll_sessions/{}".format(self.poll_id, self.id),
             _kwargs=combine_kwargs(**kwargs),
         )
-        return PollSubmission(self._requester, response.json()["poll_submissions"][0])
+        return PollSession(self._requester, response.json()["poll_sessions"][0])
diff --git a/canvasapi/rubric.py b/canvasapi/rubric.py
index 5ee003f..e566cf4 100644
--- a/canvasapi/rubric.py
+++ b/canvasapi/rubric.py
@@ -26,10 +26,84 @@ class Rubric(CanvasObject):
         return Rubric(self._requester, response.json())
 
 
+class RubricAssessment(CanvasObject):
+    def __str__(self):
+        return "{}, {}".format(self.id, self.artifact_type)
+
+    def delete(self, **kwargs):
+        """
+        Delete a single RubricAssessment.
+
+        :calls: `DELETE /api/v1/courses/:course_id/rubric_associations\
+        /:rubric_association_id/rubric_assessments/:id \
+        <https://canvas.instructure.com/doc/api/rubrics.html#method.rubric_assessments.destroy>`_
+
+        :rtype: :class:`canvasapi.rubric.RubricAssessment`
+        """
+        from canvasapi.rubric import RubricAssessment
+
+        response = self._requester.request(
+            "DELETE",
+            "courses/{}/rubric_associations/{}/rubric_assessments/{}".format(
+                self.course_id, self.rubric_association_id, self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        return RubricAssessment(self._requester, response.json())
+
+    def update(self, **kwargs):
+        """
+        Update a single RubricAssessment.
+
+        :calls: `PUT /api/v1/courses/:course_id/rubric_associations\
+        /:rubric_association_id/rubric_assessments/:id \
+        <https://canvas.instructure.com/doc/api/rubrics.html#method.rubric_assessments.update>`_
+
+        :rtype: :class:`canvasapi.rubric.RubricAssessment`
+        """
+        from canvasapi.rubric import RubricAssessment
+
+        response = self._requester.request(
+            "PUT",
+            "courses/{}/rubric_associations/{}/rubric_assessments/{}".format(
+                self.course_id, self.rubric_association_id, self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        return RubricAssessment(self._requester, response.json())
+
+
 class RubricAssociation(CanvasObject):
     def __str__(self):
         return "{}, {}".format(self.id, self.association_type)
 
+    def create_rubric_assessment(self, **kwargs):
+        """
+        Create a single RubricAssessment.
+
+        :calls: `POST /api/v1/courses/:course_id/rubric_associations\
+        /:rubric_association_id/rubric_assessments \
+        <https://canvas.instructure.com/doc/api/rubrics.html#method.rubric_assessments.create>`_
+
+        :rtype: :class:`canvasapi.rubric.RubricAssessment`
+        """
+        from canvasapi.rubric import RubricAssessment
+
+        response = self._requester.request(
+            "POST",
+            "courses/{}/rubric_associations/{}/rubric_assessments".format(
+                self.course_id, self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+
+        assessment_json = response.json()
+        assessment_json.update({"course_id": self.id})
+
+        return RubricAssessment(self._requester, assessment_json)
+
     def delete(self, **kwargs):
         """
         Delete a RubricAssociation.
diff --git a/canvasapi/user.py b/canvasapi/user.py
index 3faafac..6f9adab 100644
--- a/canvasapi/user.py
+++ b/canvasapi/user.py
@@ -1,10 +1,15 @@
+from canvasapi.authentication_event import AuthenticationEvent
+from canvasapi.avatar import Avatar
 from canvasapi.calendar_event import CalendarEvent
 from canvasapi.canvas_object import CanvasObject
 from canvasapi.communication_channel import CommunicationChannel
+from canvasapi.content_export import ContentExport
+from canvasapi.content_migration import ContentMigration, Migrator
 from canvasapi.feature import Feature, FeatureFlag
 from canvasapi.folder import Folder
 from canvasapi.grade_change_log import GradeChangeEvent
 from canvasapi.license import License
+from canvasapi.page_view import PageView
 from canvasapi.paginated_list import PaginatedList
 from canvasapi.pairing_code import PairingCode
 from canvasapi.upload import FileOrPathLike, Uploader
@@ -81,8 +86,6 @@ class User(CanvasObject):
 
         :rtype: :class:`canvasapi.content_migration.ContentMigration`
         """
-        from canvasapi.content_migration import ContentMigration, Migrator
-
         if isinstance(migration_type, Migrator):
             kwargs["migration_type"] = migration_type.type
         elif isinstance(migration_type, str):
@@ -165,8 +168,6 @@ class User(CanvasObject):
 
         :rtype: :class:`canvasapi.content_export.ContentExport`
         """
-        from canvasapi.content_export import ContentExport
-
         kwargs["export_type"] = export_type
 
         response = self._requester.request(
@@ -213,8 +214,6 @@ class User(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
                 :class:`canvasapi.authentication_event.AuthenticationEvent`
         """
-        from canvasapi.authentication_event import AuthenticationEvent
-
         return PaginatedList(
             AuthenticationEvent,
             self._requester,
@@ -233,8 +232,6 @@ class User(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.avatar.Avatar`
         """
-        from canvasapi.avatar import Avatar
-
         return PaginatedList(
             Avatar,
             self._requester,
@@ -349,8 +346,6 @@ class User(CanvasObject):
 
         :rtype: :class:`canvasapi.content_export.ContentExport`
         """
-        from canvasapi.content_export import ContentExport
-
         export_id = obj_or_id(content_export, "content_export", (ContentExport,))
 
         response = self._requester.request(
@@ -371,8 +366,6 @@ class User(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.content_export.ContentExport`
         """
-        from canvasapi.content_export import ContentExport
-
         return PaginatedList(
             ContentExport,
             self._requester,
@@ -458,18 +451,16 @@ class User(CanvasObject):
         :calls: `GET /api/v1/users/:user_id/features/enabled \
         <https://canvas.instructure.com/doc/api/feature_flags.html#method.feature_flags.enabled_features>`_
 
-        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
-            :class:`canvasapi.feature.Feature`
+        :rtype: `list` of `str`
         """
-        return PaginatedList(
-            Feature,
-            self._requester,
+        response = self._requester.request(
             "GET",
             "users/{}/features/enabled".format(self.id),
-            {"user_id": self.id},
             _kwargs=combine_kwargs(**kwargs),
         )
 
+        return response.json()
+
     def get_enrollments(self, **kwargs):
         """
         List all of the enrollments for this user.
@@ -821,8 +812,6 @@ class User(CanvasObject):
         :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
             :class:`canvasapi.course.PageView`
         """
-        from canvasapi.page_view import PageView
-
         return PaginatedList(
             PageView,
             self._requester,
@@ -1019,6 +1008,26 @@ class User(CanvasObject):
         )
         return User(self._requester, response.json())
 
+    def terminate_sessions(self, **kwargs):
+        """
+        Terminate all sessions for a user.
+
+        This includes all browser-based sessions and all access tokens,
+        including manually generated ones.
+
+        :calls: `DELETE /api/v1/users/:id/sessions \
+        <https://canvas.instructure.com/doc/api/users.html#method.users.terminate_sessions>`_
+
+        :rtype: str
+        """
+
+        response = self._requester.request(
+            "DELETE",
+            "users/{}/sessions".format(self.id),
+            _kwargs=combine_kwargs(**kwargs),
+        )
+        return response.json()
+
     def update_color(self, asset_string, hexcode, **kwargs):
         """
         Update a custom color for this user for a given context.
diff --git a/docs/account-calendar-ref.rst b/docs/account-calendar-ref.rst
new file mode 100644
index 0000000..4e213f4
--- /dev/null
+++ b/docs/account-calendar-ref.rst
@@ -0,0 +1,6 @@
+===============
+AccountCalendar
+===============
+
+.. autoclass:: canvasapi.account_calendar.AccountCalendar
+    :members:
diff --git a/docs/assignment-ref.rst b/docs/assignment-ref.rst
index dd1e5ea..bd8f21d 100644
--- a/docs/assignment-ref.rst
+++ b/docs/assignment-ref.rst
@@ -15,4 +15,10 @@ AssignmentExtension
 AssignmentGroup
 ===============
 .. autoclass:: canvasapi.assignment.AssignmentGroup
-    :members:
\ No newline at end of file
+    :members:
+
+==================
+AssignmentOverride
+==================
+.. autoclass:: canvasapi.assignment.AssignmentOverride
+    :members:
diff --git a/docs/class-reference.rst b/docs/class-reference.rst
index 21c0f2c..7420abf 100644
--- a/docs/class-reference.rst
+++ b/docs/class-reference.rst
@@ -5,6 +5,7 @@ Class Reference
 
     canvas-ref
     account-ref
+    account-calendar-ref
     appointment-group-ref
     assignment-ref
     authentication-event-ref
@@ -21,6 +22,7 @@ Class Reference
     conversation-ref
     course-ref
     course-epub-export-ref
+    course-event-ref
     current-user-ref
     custom-gradebook-columns-ref
     discussion-entry-ref
@@ -36,6 +38,7 @@ Class Reference
     grading-period-ref
     grade-change-log-ref
     group-ref
+    jwt-ref
     login-ref
     license-ref
     module-ref
diff --git a/docs/conf.py b/docs/conf.py
index 9d54463..a05eaed 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -18,7 +18,7 @@ import sys
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('../'))
+sys.path.insert(0, os.path.abspath("../"))
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -28,37 +28,34 @@ from canvasapi import __version__  # isort:skip
 
 # -- General configuration ------------------------------------------------
 # If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
 
 # Include class __init__ in autodoc
-autoclass_content = 'both'
+autoclass_content = "both"
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = [
-    'sphinx.ext.autodoc',
-    'versionwarning.extension'
-]
+extensions = ["sphinx.ext.autodoc", "versionwarning.extension"]
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # The suffix(es) of source filenames.
 # You can specify multiple suffix as a list of string:
 # source_suffix = ['.rst', '.md']
-source_suffix = '.rst'
+source_suffix = ".rst"
 
 # The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
 
 # The master toctree document.
-master_doc = 'index'
+master_doc = "index"
 
 # General information about the project.
-project = u'canvasapi'
-copyright = u'2017, University of Central Florida (Center for Distributed Learning)'
-author = u'University of Central Florida (Center for Distributed Learning)'
+project = "canvasapi"
+copyright = "2017, University of Central Florida (Center for Distributed Learning)"
+author = "University of Central Florida (Center for Distributed Learning)"
 
 
 # The short X.Y version.
@@ -68,7 +65,7 @@ release = __version__
 
 # sphinx-version-warning configuration
 versionwarning_messages = {
-    'develop': 'You are viewing a development build of the canvasapi docs. <a href="/en/stable">Visit the stable release docs here.</a>',
+    "develop": 'You are viewing a development build of the canvasapi docs. <a href="/en/stable">Visit the stable release docs here.</a>',
 }
 versionwarning_body_selector = "ul.wy-breadcrumbs"
 
@@ -81,38 +78,38 @@ language = None
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
-#today = ''
+# today = ''
 # Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
 
 # The reST default role (used for this markup: `text`) to use for all
 # documents.
-#default_role = None
+# default_role = None
 
 # If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
 
 # If true, the current module name will be prepended to all description
 # unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
 
 # If true, sectionauthor and moduleauthor directives will be shown in the
 # output. They are ignored by default.
-#show_authors = False
+# show_authors = False
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
 
 # A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
 
 # If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
+# keep_warnings = False
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
 todo_include_todos = False
@@ -122,31 +119,31 @@ todo_include_todos = False
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'sphinx_rtd_theme'
+html_theme = "sphinx_rtd_theme"
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
 # documentation.
-#html_theme_options = {}
+# html_theme_options = {}
 
 # Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
 
 # The name for this set of Sphinx documents.
 # "<project> v<release> documentation" by default.
-#html_title = u'canvasapi v1.0'
+# html_title = u'canvasapi v1.0'
 
 # A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
 
 # The name of an image file (relative to this directory) to place at the top
 # of the sidebar.
-#html_logo = None
+# html_logo = None
 
 # The name of an image file (relative to this directory) to use as a favicon of
 # the docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
 # pixels large.
-#html_favicon = None
+# html_favicon = None
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
@@ -156,124 +153,123 @@ html_static_path = []
 # Add any extra paths that contain custom files (such as robots.txt or
 # .htaccess) here, relative to this directory. These files are copied
 # directly to the root of the documentation.
-#html_extra_path = []
+# html_extra_path = []
 
 # If not None, a 'Last updated on:' timestamp is inserted at every page
 # bottom, using the given strftime format.
 # The empty string is equivalent to '%b %d, %Y'.
-#html_last_updated_fmt = None
+# html_last_updated_fmt = None
 
 # If true, SmartyPants will be used to convert quotes and dashes to
 # typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
 
 # Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
 
 # Additional templates that should be rendered to pages, maps page names to
 # template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
 
 # If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
 
 # If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
 
 # If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
 
 # If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
 
 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
 
 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
 
 # If true, an OpenSearch description file will be output, and all pages will
 # contain a <link> tag referring to it.  The value of this option must be the
 # base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
 
 # This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
 
 # Language to be used for generating the HTML full-text search index.
 # Sphinx supports the following languages:
 #   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
 #   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
-#html_search_language = 'en'
+# html_search_language = 'en'
 
 # A dictionary with options for the search language support, empty by default.
 # 'ja' uses this config value.
 # 'zh' user can custom change `jieba` dictionary path.
-#html_search_options = {'type': 'default'}
+# html_search_options = {'type': 'default'}
 
 # The name of a javascript file (relative to the configuration directory) that
 # implements a search results scorer. If empty, the default will be used.
-#html_search_scorer = 'scorer.js'
+# html_search_scorer = 'scorer.js'
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'canvasapidoc'
+htmlhelp_basename = "canvasapidoc"
 
 # -- Options for LaTeX output ---------------------------------------------
 
 latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-
-# Latex figure (float) alignment
-#'figure_align': 'htbp',
+    # The paper size ('letterpaper' or 'a4paper').
+    #'papersize': 'letterpaper',
+    # The font size ('10pt', '11pt' or '12pt').
+    #'pointsize': '10pt',
+    # Additional stuff for the LaTeX preamble.
+    #'preamble': '',
+    # Latex figure (float) alignment
+    #'figure_align': 'htbp',
 }
 
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-    (master_doc, 'canvasapi.tex', u'canvasapi Documentation',
-     u'University of Central Florida (Center for Distributed Learning)', 'manual'),
+    (
+        master_doc,
+        "canvasapi.tex",
+        "canvasapi Documentation",
+        "University of Central Florida (Center for Distributed Learning)",
+        "manual",
+    ),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
-#latex_logo = None
+# latex_logo = None
 
 # For "manual" documents, if this is true, then toplevel headings are parts,
 # not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
 
 # If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
 
 # If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
 
 # Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
 
 # If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
 
 
 # -- Options for manual page output ---------------------------------------
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
-man_pages = [
-    (master_doc, 'canvasapi', u'canvasapi Documentation',
-     [author], 1)
-]
+man_pages = [(master_doc, "canvasapi", "canvasapi Documentation", [author], 1)]
 
 # If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
 
 
 # -- Options for Texinfo output -------------------------------------------
@@ -282,19 +278,25 @@ man_pages = [
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-    (master_doc, 'canvasapi', u'canvasapi Documentation',
-     author, 'canvasapi', 'One line description of project.',
-     'Miscellaneous'),
+    (
+        master_doc,
+        "canvasapi",
+        "canvasapi Documentation",
+        author,
+        "canvasapi",
+        "One line description of project.",
+        "Miscellaneous",
+    ),
 ]
 
 # Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
 
 # If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
 
 # How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
 
 # If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
+# texinfo_no_detailmenu = False
diff --git a/docs/course-event-ref.rst b/docs/course-event-ref.rst
new file mode 100644
index 0000000..750fd27
--- /dev/null
+++ b/docs/course-event-ref.rst
@@ -0,0 +1,6 @@
+===========
+CourseEvent
+===========
+
+.. autoclass:: canvasapi.course_event.CourseEvent
+    :members:
diff --git a/docs/jwt-ref.rst b/docs/jwt-ref.rst
new file mode 100644
index 0000000..0718442
--- /dev/null
+++ b/docs/jwt-ref.rst
@@ -0,0 +1,6 @@
+===
+JWT
+===
+
+.. autoclass:: canvasapi.jwt.JWT
+    :members:
diff --git a/docs/rubric-ref.rst b/docs/rubric-ref.rst
index b02aaa2..14c36d3 100644
--- a/docs/rubric-ref.rst
+++ b/docs/rubric-ref.rst
@@ -5,6 +5,13 @@ Rubric
 .. autoclass:: canvasapi.rubric.Rubric
     :members:
 
+================
+RubricAssessment
+================
+
+.. autoclass:: canvasapi.rubric.RubricAssessment
+    :members:
+
 ==================
 Rubric Association
 ==================
diff --git a/scripts/find_missing_kwargs.py b/scripts/find_missing_kwargs.py
index 92969a8..a40b3b7 100644
--- a/scripts/find_missing_kwargs.py
+++ b/scripts/find_missing_kwargs.py
@@ -15,6 +15,8 @@ WHITELIST = (
     "Uploader.request_upload_token",
     "Uploader.start",
     "Uploader.upload",
+    "OutcomeGroup.context_ref",
+    "OutcomeLink.context_ref",
 )
 
 
diff --git a/scripts/find_missing_modules.py b/scripts/find_missing_modules.py
new file mode 100644
index 0000000..37c205a
--- /dev/null
+++ b/scripts/find_missing_modules.py
@@ -0,0 +1,49 @@
+import inspect
+import os
+import sys
+
+sys.path.append(os.path.join(sys.path[0], ".."))
+
+import canvasapi  # noqa
+
+exempt_files = ("__init__",)
+
+
+def find_missing_modules():
+    # get all modules visile to inspect from `canvasapi.__init__`
+    module_names = [
+        module_name
+        for module_name, module in inspect.getmembers(canvasapi, inspect.ismodule)
+    ]
+
+    # get all .py files in canvasapi dir (without .py extension)
+    path = "canvasapi"
+    filenames = [fname[:-3] for fname in os.listdir(path) if fname.endswith(".py")]
+
+    missing_modules = list()
+
+    for filename in filenames:
+        # ignore exempt files
+        if filename in exempt_files:
+            continue
+
+        # check for missing files against module names
+        if filename not in module_names:
+            missing_modules.append(filename)
+
+    return missing_modules
+
+
+if __name__ == "__main__":
+    missing_modules = find_missing_modules()
+    num_missing = len(missing_modules)
+    missing_module_str = ", ".join(missing_modules)
+
+    if missing_modules:
+        print(f"Missing {num_missing} modules from inspect. 💥")
+        for module in missing_modules:
+            print(f"  - {module}")
+        print("Ensure the above modules are imported (even indirectly) to __init__")
+    else:
+        print("All modules accounted for! 👍")
+    sys.exit(num_missing > 0)
diff --git a/scripts/validate_docstrings.py b/scripts/validate_docstrings.py
index 4cf4b2e..9f223ad 100644
--- a/scripts/validate_docstrings.py
+++ b/scripts/validate_docstrings.py
@@ -5,7 +5,7 @@ import sys
 
 import requests
 
-sys.path.append(os.path.join(sys.path[0], '..'))
+sys.path.append(os.path.join(sys.path[0], ".."))
 
 import canvasapi  # noqa
 
@@ -16,21 +16,20 @@ def validate_method(themethod, quiet=False):
         return True
 
     # Docstrings without API calls can't be checked this way
-    if not re.search(r':calls:', inspect.getdoc(themethod)):
+    if not re.search(r":calls:", inspect.getdoc(themethod)):
         return True
-    if not re.search(r'<\S*>', inspect.getdoc(themethod)):
+    if not re.search(r"<\S*>", inspect.getdoc(themethod)):
         return True
 
     method_string = inspect.getfile(themethod) + " " + themethod.__name__
     call_lines = re.findall(
-        '`(POST|GET|PUT|PATCH|DELETE)([^<]*)<([^>]*)>`_',
-        inspect.getdoc(themethod)
+        "`(POST|GET|PUT|PATCH|DELETE)([^<]*)<([^>]*)>`_", inspect.getdoc(themethod)
     )
     if not call_lines:
         if not quiet:
             # Docstring exists, has a :calls: line, contains a URL, but could
             # not be parsed;
-            print('{} Failed to parse :calls: line.'.format(method_string))
+            print("{} Failed to parse :calls: line.".format(method_string))
         return False
     for call_line in call_lines:
         if not validate_docstring(method_string, call_line, quiet):
@@ -40,65 +39,62 @@ def validate_method(themethod, quiet=False):
 
 def validate_docstring(method_string, call_line, quiet):
     docstring_verb, api_URL, doc_URL = call_line
-    api_URL = ''.join(api_URL.split())
-    if api_URL[-1] == '/':
+    api_URL = "".join(api_URL.split())
+    if api_URL[-1] == "/":
         api_URL = api_URL[0:-1]
-    docfile_URL, endpoint_name = re.search('([^#]*)#?(.*)', doc_URL).groups()
+    docfile_URL, endpoint_name = re.search("([^#]*)#?(.*)", doc_URL).groups()
     html_doc_response = requests.get(docfile_URL)
     if html_doc_response.status_code != requests.codes.ok:
         if not quiet:
-            print('{} docstring URL request returned {}'.format(
-                method_string,
-                html_doc_response.status_code
-            ))
+            print(
+                "{} docstring URL request returned {}".format(
+                    method_string, html_doc_response.status_code
+                )
+            )
         return False
 
     endpoint_h2 = re.search(
-        r'<h2[^>]*name=[\'\"]{}[\'\"]'.format(endpoint_name),
-        html_doc_response.text
+        r"<h2[^>]*name=[\'\"]{}[\'\"]".format(endpoint_name), html_doc_response.text
     )
     if not endpoint_name:
         if not quiet:
-            print((
-                '{} docstring URL does not contain an endpoint name in link'
-                ' to API documentation'
-            ).format(method_string))
+            print(
+                (
+                    "{} docstring URL does not contain an endpoint name in link"
+                    " to API documentation"
+                ).format(method_string)
+            )
         return False
     if not endpoint_h2:
         if not quiet:
-            print('{} docstring refers to {} in {}, not found'.format(
-                method_string, endpoint_name, docfile_URL
-            ))
+            print(
+                "{} docstring refers to {} in {}, not found".format(
+                    method_string, endpoint_name, docfile_URL
+                )
+            )
         return False
 
-    endpoint_element_re = re.compile(
-        r'<h3 class=[\"\']endpoint[\"\']>[^<]*<\/h3>'
-    )
+    endpoint_element_re = re.compile(r"<h3 class=[\"\']endpoint[\"\']>[^<]*<\/h3>")
 
     endpoint_search_start_match = endpoint_element_re.search(
-        html_doc_response.text,
-        endpoint_h2.end()
+        html_doc_response.text, endpoint_h2.end()
     )
     if not endpoint_search_start_match:
         if not quiet:
-            print('Found no endpoint after {} in {}'.format(
-                endpoint_name,
-                docfile_URL
-            ))
+            print("Found no endpoint after {} in {}".format(endpoint_name, docfile_URL))
         return False
 
     endpoint_search_start_pos = endpoint_search_start_match.start()
-    after_endpoint_re = re.compile(r'<[^h\/]')
-    endpoint_search_end = after_endpoint_re.search(html_doc_response.text,
-                                                   endpoint_search_start_pos)
+    after_endpoint_re = re.compile(r"<[^h\/]")
+    endpoint_search_end = after_endpoint_re.search(
+        html_doc_response.text, endpoint_search_start_pos
+    )
     if not endpoint_search_end:
         endpoint_search_stop_pos = len(html_doc_response.text)
     else:
         endpoint_search_stop_pos = endpoint_search_end.start()
     endpoint_element_match = endpoint_element_re.search(
-        html_doc_response.text,
-        endpoint_search_start_pos,
-        endpoint_search_stop_pos
+        html_doc_response.text, endpoint_search_start_pos, endpoint_search_stop_pos
     )
     endpoint_element_list = []
     while endpoint_element_match:
@@ -106,21 +102,17 @@ def validate_docstring(method_string, call_line, quiet):
         endpoint_element_match = endpoint_element_re.search(
             html_doc_response.text,
             endpoint_element_match.end(),
-            endpoint_search_stop_pos
+            endpoint_search_stop_pos,
         )
 
     if not endpoint_element_list:
         if not quiet:
-            print('Found no endpoint after {} in {}'.format(
-                endpoint_name,
-                docfile_URL
-            ))
+            print("Found no endpoint after {} in {}".format(endpoint_name, docfile_URL))
         return False
     docfile_lines = []
     for endpoint_element_str in endpoint_element_list:
         docfile_match = re.search(
-            '(POST|GET|PUT|PATCH|DELETE) (.*)',
-            endpoint_element_str
+            "(POST|GET|PUT|PATCH|DELETE) (.*)", endpoint_element_str
         )
         docfile_lines.append(docfile_match.group())
         docfile_verb, docfile_API_URL = docfile_match.groups()
@@ -130,12 +122,14 @@ def validate_docstring(method_string, call_line, quiet):
             continue
         return True
     if not quiet:
-        print('{} docstring {} not found in {} (found {})'.format(
-            method_string,
-            docstring_verb + ' ' + api_URL,
-            doc_URL,
-            str(docfile_lines)
-        ))
+        print(
+            "{} docstring {} not found in {} (found {})".format(
+                method_string,
+                docstring_verb + " " + api_URL,
+                doc_URL,
+                str(docfile_lines),
+            )
+        )
     return False
 
 
@@ -149,5 +143,5 @@ def test_methods():
         validate_method(method_to_test)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     test_methods()


Test patch:
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index 76c1c57..6a22947 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -33,11 +33,14 @@ jobs:
         run: coverage run -m unittest discover
       - name: Lint markdown files
         uses: bewuethr/mdl-action@v1
+      - name: Check if all modules are visible to inspect
+        run: python scripts/find_missing_modules.py
       - name: Check if methods are alphabetical
         run: python scripts/alphabetic.py
       - name: Check for missing kwargs
         run: python scripts/find_missing_kwargs.py
       - name: Upload coverage to Codecov
-        uses: codecov/codecov-action@v1
+        uses: codecov/codecov-action@v3
         with:
           fail_ci_if_error: true
+          token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh
index c8f3809..00ae4ca 100755
--- a/scripts/run_tests.sh
+++ b/scripts/run_tests.sh
@@ -7,5 +7,6 @@ black --check canvasapi tests
 isort --check canvasapi tests
 flake8 canvasapi tests
 mdl . .github
+python scripts/find_missing_modules.py
 python scripts/alphabetic.py
 python scripts/find_missing_kwargs.py
diff --git a/tests/fixtures/account.json b/tests/fixtures/account.json
index a9feaef..673581e 100644
--- a/tests/fixtures/account.json
+++ b/tests/fixtures/account.json
@@ -8,7 +8,7 @@
 			"start_at": "2015-04-01T00:00:00Z",
 			"end_at": "2018-04-01T00:00:00Z"
 		},
-		"status_code":  200
+		"status_code": 200
 	},
 	"create": {
 		"method": "POST",
@@ -150,6 +150,68 @@
 		},
 		"status_code": 200
 	},
+	"get_account_calendars": {
+		"method": "GET",
+		"endpoint": "account_calendars",
+		"data": [
+			{
+				"id": 1,
+				"name": "CDL",
+				"calendar_event_url": "calendarURL",
+				"visible": true
+			},
+			{
+				"id": 2,
+				"name": "DDL",
+				"calendar_event_url": "calendarURL2",
+				"visible": true
+			}
+		]
+	},
+	"get_account_calendar": {
+		"method": "GET",
+		"endpoint": "account_calendars/1",
+		"data": {
+			"id": 10,
+			"name": "Department of Computer Science",
+			"calendar_event_url": "calendarURL",
+			"visible": true
+		}
+	},
+	"get_all_account_calendars": {
+		"method": "GET",
+		"endpoint": "accounts/1/account_calendars",
+		"data": [
+			{
+				"id": 1,
+				"name": "FSU"
+			},
+			{
+				"id": 2,
+				"name": "Full Sail"
+			}
+		]
+	},
+	"update_account_calendar_visibility": {
+		"method": "PUT",
+		"endpoint": "account_calendars/1",
+		"data": {
+			"id": 102,
+			"name": "Department of Aerospace Engineering",
+			"calendar_event_url": "calendarURL",
+			"visible": true
+		}
+	},
+	"update_many_account_calendars_visibility": {
+		"method": "PUT",
+		"endpoint": "accounts/1/account_calendars",
+		"data": {
+			"id": 1,
+			"name": "Biology Department",
+			"calendar_event_url": "calendarURL",
+			"visible": true
+		}
+	},
 	"get_by_id": {
 		"method": "GET",
 		"endpoint": "accounts/1",
@@ -329,48 +391,53 @@
 		"endpoint": "accounts/1/terms",
 		"data": {
 			"enrollment_terms": [
-			{
-				"id": 1,
-				"name": "Enrollment Term 1"
-			},
-			{
-				"id": 2,
-				"name": "Enrollment Term 2"
-			}]
+				{
+					"id": 1,
+					"name": "Enrollment Term 1"
+				},
+				{
+					"id": 2,
+					"name": "Enrollment Term 2"
+				}
+			]
 		},
 		"status_code": 200
 	},
 	"get_notification": {
 		"method": "GET",
 		"endpoint": "accounts/1/account_notifications/1",
-		"data":{
-  			"subject": "Attention Students",
-  			"message": "This is a test of the notification system.",
-  			"start_at": "2013-08-28T23:59:00-06:00",
-  			"end_at": "2013-08-29T23:59:00-06:00",
-  			"icon": "information",
-  			"roles": ["StudentEnrollment"],
-  			"role_ids": [1]
+		"data": {
+			"subject": "Attention Students",
+			"message": "This is a test of the notification system.",
+			"start_at": "2013-08-28T23:59:00-06:00",
+			"end_at": "2013-08-29T23:59:00-06:00",
+			"icon": "information",
+			"roles": [
+				"StudentEnrollment"
+			],
+			"role_ids": [
+				1
+			]
 		},
 		"status_code": 200
 	},
 	"get_grading_periods": {
-        "method": "GET",
-        "endpoint": "accounts/1/grading_periods",
-        "data": {
-            "grading_periods": [
-                {
-                    "title": "Grading period 1",
-                    "id": 1
-                },
-                {
-                    "title": "Grading period 2",
-                    "id": 2
-                }
-            ]
-        },
-        "status_code": 200
-    },
+		"method": "GET",
+		"endpoint": "accounts/1/grading_periods",
+		"data": {
+			"grading_periods": [
+				{
+					"title": "Grading period 1",
+					"id": 1
+				},
+				{
+					"title": "Grading period 2",
+					"id": 2
+				}
+			]
+		},
+		"status_code": 200
+	},
 	"get_groups_context": {
 		"method": "GET",
 		"endpoint": "accounts/1/groups",
@@ -404,6 +471,24 @@
 		],
 		"status_code": 200
 	},
+	"query_audit_by_account": {
+		"method": "GET",
+		"endpoint": "audit/course/accounts/1",
+		"data": [
+			{
+				"id": 1,
+				"name": "UCF",
+				"start_at": "2022-11-18T05:00:00-06:00",
+				"conclude_at": "2022-11-18T15:00:00-06:00"
+			},
+			{
+				"id": 2,
+				"name": "FSU",
+				"start_at": "2022-11-18T05:00:00-06:00",
+				"conclude_at": "2022-11-18T15:00:00-06:00"
+			}
+		]
+	},
 	"multiple": {
 		"method": "GET",
 		"endpoint": "accounts",
@@ -458,9 +543,9 @@
 		],
 		"status_code": 200
 	},
-	"get_outcome_import_status":{
-		"method" : "GET",
-		"endpoint" : "accounts/1/outcome_imports/1",
+	"get_outcome_import_status": {
+		"method": "GET",
+		"endpoint": "accounts/1/outcome_imports/1",
 		"data": {
 			"id": 1,
 			"created_at": "2013-12-01T23:59:00-06:00",
@@ -475,9 +560,9 @@
 		},
 		"status_code": 200
 	},
-	"get_outcome_import_status_latest":{
-		"method" : "GET",
-		"endpoint" : "accounts/1/outcome_imports/latest",
+	"get_outcome_import_status_latest": {
+		"method": "GET",
+		"endpoint": "accounts/1/outcome_imports/latest",
 		"data": {
 			"id": 1,
 			"created_at": "2013-12-01T23:59:00-06:00",
@@ -492,93 +577,93 @@
 		},
 		"status_code": 200
 	},
-	"create_report":{
+	"create_report": {
 		"method": "POST",
 		"endpoint": "accounts/1/reports/zero_activity_csv",
 		"data": {
-        	"title": "Zero Activity",
-        	"parameters": {
-            	"enrollment_term_id": {
-                	"required": false,
-                	"description": "The canvas id of the term to get grades from"
-            	},
-            	"start_at": {
-                	"required": false,
-                	"description": "The first date in the date range, the second date is the time the report is run."
-            	},
-            	"course_id": {
-                	"required": false,
-                	"description": "The course to report on"
-            	}
-        },
-        "report": "zero_activity_csv",
-        "last_run": null
+			"title": "Zero Activity",
+			"parameters": {
+				"enrollment_term_id": {
+					"required": false,
+					"description": "The canvas id of the term to get grades from"
+				},
+				"start_at": {
+					"required": false,
+					"description": "The first date in the date range, the second date is the time the report is run."
+				},
+				"course_id": {
+					"required": false,
+					"description": "The course to report on"
+				}
+			},
+			"report": "zero_activity_csv",
+			"last_run": null
 		},
 		"status_code": 200
 	},
-	"delete_report":{
+	"delete_report": {
 		"method": "DELETE",
 		"endpoint": "accounts/1/reports/zero_activity_csv/1",
 		"data": {
-    		"id": 1,
-    		"progress": 100,
-    		"parameters": {
-    		    "extra_text": "Term: All Terms;"
-    		},
-    		"current_line": 1,
-    		"status": "deleted",
-    		"report": "zero_activity_csv",
-    		"created_at": "2019-08-13T15:23:15-04:00",
-    		"started_at": "2019-08-13T15:23:17-04:00",
-    		"ended_at": "2019-08-13T15:23:17-04:00",
-    		"file_url": "xxxxxxxxxxxxxxxxxxxxxxx",
-    		"attachment": {
-    		    "id": 1,
-    		    "uuid": "CCVh71fQEPsDqc4VOoGBr5llCbzAeLEpBcWcAe88",
-    		    "folder_id": 1,
-    		    "display_name": "zero_activity_csv_xxxxxxxxxxxxxxxxxxxxxxx.csv",
-    		    "filename": "zero_activity_csv_xxxxxxxxxxxxxxxxxxxxxxx.csv",
-    		    "workflow_state": "processed",
-    		    "upload_status": "success",
-    		    "content-type": "text/csv",
-    		    "url": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
-    		    "size": 100,
-    		    "created_at": "2019-08-13T19:23:17Z",
-    		    "updated_at": "2019-08-13T19:23:17Z",
-    		    "unlock_at": null,
-    		    "locked": false,
-    		    "hidden": false,
-    		    "lock_at": null,
-    		    "hidden_for_user": false,
-    		    "thumbnail_url": null,
-    		    "modified_at": "2019-08-13T19:23:17Z",
-    		    "mime_class": "file",
-    		    "media_entry_id": null,
-    		    "locked_for_user": false
-    			}
+			"id": 1,
+			"progress": 100,
+			"parameters": {
+				"extra_text": "Term: All Terms;"
+			},
+			"current_line": 1,
+			"status": "deleted",
+			"report": "zero_activity_csv",
+			"created_at": "2019-08-13T15:23:15-04:00",
+			"started_at": "2019-08-13T15:23:17-04:00",
+			"ended_at": "2019-08-13T15:23:17-04:00",
+			"file_url": "xxxxxxxxxxxxxxxxxxxxxxx",
+			"attachment": {
+				"id": 1,
+				"uuid": "CCVh71fQEPsDqc4VOoGBr5llCbzAeLEpBcWcAe88",
+				"folder_id": 1,
+				"display_name": "zero_activity_csv_xxxxxxxxxxxxxxxxxxxxxxx.csv",
+				"filename": "zero_activity_csv_xxxxxxxxxxxxxxxxxxxxxxx.csv",
+				"workflow_state": "processed",
+				"upload_status": "success",
+				"content-type": "text/csv",
+				"url": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+				"size": 100,
+				"created_at": "2019-08-13T19:23:17Z",
+				"updated_at": "2019-08-13T19:23:17Z",
+				"unlock_at": null,
+				"locked": false,
+				"hidden": false,
+				"lock_at": null,
+				"hidden_for_user": false,
+				"thumbnail_url": null,
+				"modified_at": "2019-08-13T19:23:17Z",
+				"mime_class": "file",
+				"media_entry_id": null,
+				"locked_for_user": false
+			}
 		}
 	},
-	"get_report":{
+	"get_report": {
 		"method": "GET",
 		"endpoint": "accounts/1/reports/zero_activity_csv/1",
-		"data":{
-        	"title": "Zero Activity",
-        	"parameters": {
-            	"enrollment_term_id": {
-                	"required": false,
-                	"description": "The canvas id of the term to get grades from"
-            	},
-            	"start_at": {
-                	"required": false,
-                	"description": "The first date in the date range, the second date is the time the report is run."
-            	},
-            	"course_id": {
-                	"required": false,
-                	"description": "The course to report on"
-            	}
-        },
-        "report": "zero_activity_csv",
-        "last_run": null
+		"data": {
+			"title": "Zero Activity",
+			"parameters": {
+				"enrollment_term_id": {
+					"required": false,
+					"description": "The canvas id of the term to get grades from"
+				},
+				"start_at": {
+					"required": false,
+					"description": "The first date in the date range, the second date is the time the report is run."
+				},
+				"course_id": {
+					"required": false,
+					"description": "The course to report on"
+				}
+			},
+			"report": "zero_activity_csv",
+			"last_run": null
 		},
 		"status_code": 200
 	},
@@ -780,10 +865,10 @@
 		"method": "PUT",
 		"endpoint": "accounts/1/account_notifications/1",
 		"data": {
-            "subject": "subject",
-            "message": "Message",
-            "start_at": "2015-04-01T00:00:00Z",
-            "end_at": "2018-04-01T00:00:00Z"
+			"subject": "subject",
+			"message": "Message",
+			"start_at": "2015-04-01T00:00:00Z",
+			"end_at": "2018-04-01T00:00:00Z"
 		},
 		"status_code": 200
 	},
@@ -872,7 +957,7 @@
 	"create_role": {
 		"method": "POST",
 		"endpoint": "accounts/1/roles",
-		"data":{
+		"data": {
 			"id": 1,
 			"role": "StudentEnrollment",
 			"label": "Student"
@@ -1030,22 +1115,22 @@
 		"endpoint": "accounts/1/analytics/terms/1/grades",
 		"data": [
 			{
-			  "0": "13435",
-			  "1": "41",
-			  "2": "58",
-			  "3": "27",
-			  "68": "1387",
-			  "69": "1412",
-			  "70": "2199",
-			  "85": "5575",
-			  "86": "6543",
-			  "87": "6144",
-			  "88": "7198",
-			  "89": "6561",
-			  "90": "8854",
-			  "91": "7745",
-			  "92": "8800",
-			  "93": "7798"
+				"0": "13435",
+				"1": "41",
+				"2": "58",
+				"3": "27",
+				"68": "1387",
+				"69": "1412",
+				"70": "2199",
+				"85": "5575",
+				"86": "6543",
+				"87": "6144",
+				"88": "7198",
+				"89": "6561",
+				"90": "8854",
+				"91": "7745",
+				"92": "8800",
+				"93": "7798"
 			}
 		]
 	},
@@ -1054,22 +1139,22 @@
 		"endpoint": "accounts/1/analytics/current/grades",
 		"data": [
 			{
-			  "0": "13435",
-			  "1": "41",
-			  "2": "58",
-			  "3": "27",
-			  "68": "1387",
-			  "69": "1412",
-			  "70": "2199",
-			  "85": "5575",
-			  "86": "6543",
-			  "87": "6144",
-			  "88": "7198",
-			  "89": "6561",
-			  "90": "8854",
-			  "91": "7745",
-			  "92": "8800",
-			  "93": "7798"
+				"0": "13435",
+				"1": "41",
+				"2": "58",
+				"3": "27",
+				"68": "1387",
+				"69": "1412",
+				"70": "2199",
+				"85": "5575",
+				"86": "6543",
+				"87": "6144",
+				"88": "7198",
+				"89": "6561",
+				"90": "8854",
+				"91": "7745",
+				"92": "8800",
+				"93": "7798"
 			}
 		]
 	},
@@ -1078,22 +1163,22 @@
 		"endpoint": "accounts/1/analytics/completed/grades",
 		"data": [
 			{
-			  "0": "13435",
-			  "1": "41",
-			  "2": "58",
-			  "3": "27",
-			  "68": "1387",
-			  "69": "1412",
-			  "70": "2199",
-			  "85": "5575",
-			  "86": "6543",
-			  "87": "6144",
-			  "88": "7198",
-			  "89": "6561",
-			  "90": "8854",
-			  "91": "7745",
-			  "92": "8800",
-			  "93": "7798"
+				"0": "13435",
+				"1": "41",
+				"2": "58",
+				"3": "27",
+				"68": "1387",
+				"69": "1412",
+				"70": "2199",
+				"85": "5575",
+				"86": "6543",
+				"87": "6144",
+				"88": "7198",
+				"89": "6561",
+				"90": "8854",
+				"91": "7745",
+				"92": "8800",
+				"93": "7798"
 			}
 		]
 	},
@@ -1185,7 +1270,7 @@
 	"add_authentication_providers": {
 		"method": "POST",
 		"endpoint": "accounts/1/authentication_providers",
-		"data":{
+		"data": {
 			"id": 1,
 			"auth_type": "saml",
 			"position": 1
@@ -1227,11 +1312,20 @@
 			"context_id": 1,
 			"context_type": "Account",
 			"grading_scheme": [
-			  {"name": "A", "value": 0.9},
-			  {"name": "B", "value": 0.8},
-			  {"name": "C", "value": 0.7}
+				{
+					"name": "A",
+					"value": 0.9
+				},
+				{
+					"name": "B",
+					"value": 0.8
+				},
+				{
+					"name": "C",
+					"value": 0.7
+				}
 			]
-		  },
+		},
 		"status_code": 200
 	},
 	"get_grading_standards": {
@@ -1239,38 +1333,53 @@
 		"endpoint": "accounts/1/grading_standards",
 		"data": [
 			{
-			"title": "Grading Standard 1",
-			"id": 1,
-			"context_id": 1,
-			"context_type": "Account",
-			"grading_scheme": [
-			  {"name": "A", "value": 0.9},
-			  {"name": "B", "value": 0.8},
-			  {"name": "C", "value": 0.7}
-			]
-		  },
-		  {
-			"title": "Grading Standard 2",
-			"id": 2,
-			"context_id": 1,
-			"context_type": "Account",
-			"grading_scheme": [
-			  {"name": "D", "value": 0.6},
-			  {"name": "F", "value": 0.5}
-			]
-		  }
+				"title": "Grading Standard 1",
+				"id": 1,
+				"context_id": 1,
+				"context_type": "Account",
+				"grading_scheme": [
+					{
+						"name": "A",
+						"value": 0.9
+					},
+					{
+						"name": "B",
+						"value": 0.8
+					},
+					{
+						"name": "C",
+						"value": 0.7
+					}
+				]
+			},
+			{
+				"title": "Grading Standard 2",
+				"id": 2,
+				"context_id": 1,
+				"context_type": "Account",
+				"grading_scheme": [
+					{
+						"name": "D",
+						"value": 0.6
+					},
+					{
+						"name": "F",
+						"value": 0.5
+					}
+				]
+			}
 		],
 		"status_code": 200
 	},
 	"delete_grading_period": {
-        "method": "DELETE",
-        "endpoint": "accounts/1/grading_periods/1",
-        "data": {
-            "delete": true
-        },
-        "status_code": 200
-    },
-		"get_rubric_single": {
+		"method": "DELETE",
+		"endpoint": "accounts/1/grading_periods/1",
+		"data": {
+			"delete": true
+		},
+		"status_code": 200
+	},
+	"get_rubric_single": {
 		"method": "GET",
 		"endpoint": "accounts/1/rubrics/1",
 		"data": {
@@ -1324,37 +1433,46 @@
 			"context_id": 1,
 			"context_type": "Account",
 			"grading_scheme": [
-			  {"name": "A", "value": 0.9},
-			  {"name": "B", "value": 0.8},
-			  {"name": "C", "value": 0.7}
+				{
+					"name": "A",
+					"value": 0.9
+				},
+				{
+					"name": "B",
+					"value": 0.8
+				},
+				{
+					"name": "C",
+					"value": 0.7
+				}
 			]
-		  },
+		},
 		"status_code": 200
 	},
 	"get_scopes": {
-	"method": "GET",
-	"endpoint": "accounts/1/scopes",
-	"data": [
-		{
-        	"controller": "users",
-        	"action": "settings",
-        	"verb": "PUT",
-        	"path": "/api/v1/users/:id/settings",
-        	"scope": "url:PUT|/api/v1/users/:id/settings",
-        	"resource": "users",
-        	"resource_name": "Users"
-		},
-		{
-        	"controller": "course_nicknames",
-        	"action": "show",
-        	"verb": "GET",
-        	"path": "/api/v1/users/self/course_nicknames/:course_id",
-        	"scope": "url:GET|/api/v1/users/self/course_nicknames/:course_id",
-        	"resource": "users",
-        	"resource_name": "Users"
-		}
-	],
-	"status_code": 200
+		"method": "GET",
+		"endpoint": "accounts/1/scopes",
+		"data": [
+			{
+				"controller": "users",
+				"action": "settings",
+				"verb": "PUT",
+				"path": "/api/v1/users/:id/settings",
+				"scope": "url:PUT|/api/v1/users/:id/settings",
+				"resource": "users",
+				"resource_name": "Users"
+			},
+			{
+				"controller": "course_nicknames",
+				"action": "show",
+				"verb": "GET",
+				"path": "/api/v1/users/self/course_nicknames/:course_id",
+				"scope": "url:GET|/api/v1/users/self/course_nicknames/:course_id",
+				"resource": "users",
+				"resource_name": "Users"
+			}
+		],
+		"status_code": 200
 	},
 	"create_content_migration": {
 		"method": "POST",
@@ -1663,8 +1781,7 @@
 	"abort_sis_imports_pending_blank": {
 		"method": "PUT",
 		"endpoint": "accounts/1/sis_imports/abort_all_pending",
-		"data": {
-		},
+		"data": {},
 		"status_code": 200
 	},
 	"create_admin": {
@@ -1728,16 +1845,8 @@
 		"method": "GET",
 		"endpoint": "accounts/1/features/enabled",
 		"data": [
-			{
-				"name": "feature_one",
-				"display_name": "Feature One",
-				"applies_to": "Account"
-			},
-			{
-				"name": "feature_two",
-				"display_name": "Feature Two",
-				"applies_to": "Account"
-			}
+			"feature_one",
+			"feature_two"
 		],
 		"status_code": 200
 	},
diff --git a/tests/fixtures/assignment.json b/tests/fixtures/assignment.json
index 95d8cc3..cfcbd2f 100644
--- a/tests/fixtures/assignment.json
+++ b/tests/fixtures/assignment.json
@@ -490,5 +490,33 @@
 		"data": {
 			"message": "OK"
 		}
+	},
+	"get_students_selected_moderation": {
+		"method": "GET",
+		"endpoint": "courses/1/assignments/1/moderated_students",
+		"data": [
+			{
+				"id": 1,
+				"name": "John Doe"
+			},
+			{
+				"id": 2,
+				"name": "John Smith"
+			}
+		]
+	},
+	"select_students_for_moderation": {
+		"method": "POST",
+		"endpoint": "courses/1/assignments/1/moderated_students",
+		"data": [
+			{
+				"id": 11,
+				"name": "Joyce Smith"
+			},
+			{
+				"id": 12,
+				"name": "Jane Doe"
+			}
+		]
 	}
 }
diff --git a/tests/fixtures/course.json b/tests/fixtures/course.json
index cc750c9..81b3130 100644
--- a/tests/fixtures/course.json
+++ b/tests/fixtures/course.json
@@ -287,19 +287,20 @@
 		"method": "GET",
 		"endpoint": "courses/1/epub_exports/1",
 		"data": {
+			"id": 1,
+			"name": "course1",
+			"epub_export": {
 				"id": 1,
-				"name": "course1",
-				"epub_export": {
-					"id": 1,
-					"created_at": "2019-01-01T00:00:00Z",
-					"attachment": {"url":"https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"},
-					"progress_url": "https://dummyurl.com/api/v1/progress/4",
-					"user_id": 4,
-					"workflow_state": "exported"
-					}
+				"created_at": "2019-01-01T00:00:00Z",
+				"attachment": {
+					"url": "https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"
+				},
+				"progress_url": "https://dummyurl.com/api/v1/progress/4",
+				"user_id": 4,
+				"workflow_state": "exported"
+			}
 		},
 		"status_code": 200
-
 	},
 	"get_epub_exports": {
 		"method": "GET",
@@ -307,30 +308,33 @@
 		"data": {
 			"courses": [
 				{
-				"id": 1,
-				"name": "course1",
-				"epub_export": {
 					"id": 1,
-					"created_at": "2019-01-01T00:00:00Z",
-					"attachment": {"url":"https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"},
-					"progress_url": "https://dummyurl.com/api/v1/progress/4",
-					"user_id": 4,
-					"workflow_state": "exported"
+					"name": "course1",
+					"epub_export": {
+						"id": 1,
+						"created_at": "2019-01-01T00:00:00Z",
+						"attachment": {
+							"url": "https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"
+						},
+						"progress_url": "https://dummyurl.com/api/v1/progress/4",
+						"user_id": 4,
+						"workflow_state": "exported"
 					}
 				},
 				{
-				"id": 2,
-				"name": "course2",
-				"epub_export": {
 					"id": 2,
-					"created_at": "2019-06-01T00:00:00Z",
-					"attachment": {"url":"https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"},
-					"progress_url": "https://dummyurl.com/api/v1/progress/4",
-					"user_id": 5,
-					"workflow_state": "exported"
+					"name": "course2",
+					"epub_export": {
+						"id": 2,
+						"created_at": "2019-06-01T00:00:00Z",
+						"attachment": {
+							"url": "https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"
+						},
+						"progress_url": "https://dummyurl.com/api/v1/progress/4",
+						"user_id": 5,
+						"workflow_state": "exported"
 					}
 				}
-
 			]
 		},
 		"status_code": 200
@@ -339,16 +343,18 @@
 		"method": "POST",
 		"endpoint": "courses/1/epub_exports/",
 		"data": {
+			"id": 1,
+			"name": "course1",
+			"epub_export": {
 				"id": 1,
-				"name": "course1",
-				"epub_export": {
-					"id": 1,
-					"created_at": "2019-01-01T00:00:00Z",
-					"attachment": {"url":"https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"},
-					"progress_url": "https://dummyurl.com/api/v1/progress/4",
-					"user_id": 4,
-					"workflow_state": "exported"
-					}
+				"created_at": "2019-01-01T00:00:00Z",
+				"attachment": {
+					"url": "https://dummyurl.com/api/v1/attachments/789?download_frd=1&verifier=bG9sY2F0cyEh"
+				},
+				"progress_url": "https://dummyurl.com/api/v1/progress/4",
+				"user_id": 4,
+				"workflow_state": "exported"
+			}
 		},
 		"status_code": 200
 	},
@@ -475,7 +481,9 @@
 						"grading_type": "points",
 						"course_id": 1,
 						"name": "Test assignment",
-						"submission_types": ["online_text_entry"]
+						"submission_types": [
+							"online_text_entry"
+						]
 					}
 				],
 				"courses": [
@@ -498,9 +506,9 @@
 		},
 		"status_code": 200
 	},
-	"get_outcome_import_status":{
-		"method" : "GET",
-		"endpoint" : "courses/1/outcome_imports/1",
+	"get_outcome_import_status": {
+		"method": "GET",
+		"endpoint": "courses/1/outcome_imports/1",
 		"data": {
 			"id": 1,
 			"created_at": "2013-12-01T23:59:00-06:00",
@@ -515,9 +523,9 @@
 		},
 		"status_code": 200
 	},
-	"get_outcome_import_status_latest":{
-		"method" : "GET",
-		"endpoint" : "courses/1/outcome_imports/latest",
+	"get_outcome_import_status_latest": {
+		"method": "GET",
+		"endpoint": "courses/1/outcome_imports/latest",
 		"data": {
 			"id": 1,
 			"created_at": "2013-12-01T23:59:00-06:00",
@@ -544,43 +552,54 @@
 		"method": "GET",
 		"endpoint": "courses/1/quizzes/assignment_overrides",
 		"data": {
-			"quiz_assignment_overrides": [{
-				"quiz_id": "1",
-				"due_dates": [{
-					"id": 1,
-					"due_at": "2014-02-21T06:59:59Z",
-					"unlock_at": null,
-					"lock_at": "2014-02-21T06:59:59Z",
-					"title": "Project X",
-					"base": true
-				}],
-				"all_dates": [{
-					"id": 1,
-					"due_at": "2014-02-21T06:59:59Z",
-					"unlock_at": null,
-					"lock_at": "2014-02-21T06:59:59Z",
-					"title": "Project X",
-					"base": true
-				}]
-			},{
-				"quiz_id": "2",
-				"due_dates": [{
-					"id": 1,
-					"due_at": "2014-02-21T06:59:59Z",
-					"unlock_at": null,
-					"lock_at": "2014-02-21T06:59:59Z",
-					"title": "Project X",
-					"base": true
-				}],
-				"all_dates": [{
-					"id": 1,
-					"due_at": "2014-02-21T06:59:59Z",
-					"unlock_at": null,
-					"lock_at": "2014-02-21T06:59:59Z",
-					"title": "Project X",
-					"base": true
-				}]
-			}]
+			"quiz_assignment_overrides": [
+				{
+					"quiz_id": "1",
+					"due_dates": [
+						{
+							"id": 1,
+							"due_at": "2014-02-21T06:59:59Z",
+							"unlock_at": null,
+							"lock_at": "2014-02-21T06:59:59Z",
+							"title": "Project X",
+							"base": true
+						}
+					],
+					"all_dates": [
+						{
+							"id": 1,
+							"due_at": "2014-02-21T06:59:59Z",
+							"unlock_at": null,
+							"lock_at": "2014-02-21T06:59:59Z",
+							"title": "Project X",
+							"base": true
+						}
+					]
+				},
+				{
+					"quiz_id": "2",
+					"due_dates": [
+						{
+							"id": 1,
+							"due_at": "2014-02-21T06:59:59Z",
+							"unlock_at": null,
+							"lock_at": "2014-02-21T06:59:59Z",
+							"title": "Project X",
+							"base": true
+						}
+					],
+					"all_dates": [
+						{
+							"id": 1,
+							"due_at": "2014-02-21T06:59:59Z",
+							"unlock_at": null,
+							"lock_at": "2014-02-21T06:59:59Z",
+							"title": "Project X",
+							"base": true
+						}
+					]
+				}
+			]
 		},
 		"status_code": 200
 	},
@@ -661,7 +680,7 @@
 		],
 		"status_code": 200
 	},
-	"get_section":{
+	"get_section": {
 		"method": "GET",
 		"endpoint": "courses/1/sections/1",
 		"data": {
@@ -713,15 +732,15 @@
 		"endpoint": "courses/1/gradebook_history/08-23-2019/graders/1/assignments/1/submissions",
 		"data": [
 			{
-                "submission_id": 4,
-                "versions": null
-            },
-            {
-                "submission_id": 7,
-                "versions": null
-            }
-        ]
-    },
+				"submission_id": 4,
+				"versions": null
+			},
+			{
+				"submission_id": 7,
+				"versions": null
+			}
+		]
+	},
 	"todo_items": {
 		"method": "GET",
 		"endpoint": "courses/1/todo",
@@ -1215,7 +1234,7 @@
 	"show_front_page": {
 		"method": "GET",
 		"endpoint": "courses/1/front_page",
-		"data":{
+		"data": {
 			"id": 1,
 			"url": "front-page",
 			"title": "Front Page"
@@ -1399,11 +1418,10 @@
 	"get_discussion_topic": {
 		"method": "GET",
 		"endpoint": "courses/1/discussion_topics/1",
-		"data":
-			{
-				"id": 1,
-				"title": "Topic 1"
-			},
+		"data": {
+			"id": 1,
+			"title": "Topic 1"
+		},
 		"status_code": 200
 	},
 	"get_file": {
@@ -1415,16 +1433,16 @@
 			"size": 2048
 		},
 		"status_code": 200
-    },
-    "get_file_quota": {
-        "method": "GET",
-        "endpoint": "courses/1/files/quota",
-        "data": {
-            "quota": 524288000,
-            "quota_used": 402653184
-        },
-        "status_code": 200
-    },
+	},
+	"get_file_quota": {
+		"method": "GET",
+		"endpoint": "courses/1/files/quota",
+		"data": {
+			"quota": 524288000,
+			"quota_used": 402653184
+		},
+		"status_code": 200
+	},
 	"get_full_discussion_topic": {
 		"method": "GET",
 		"endpoint": "courses/1/discussion_topics/1/view",
@@ -1472,7 +1490,11 @@
 		"endpoint": "courses/1/discussion_topics/reorder",
 		"data": {
 			"reorder": true,
-			"order": [1, 2, 3]
+			"order": [
+				1,
+				2,
+				3
+			]
 		},
 		"status_code": 200
 	},
@@ -1614,7 +1636,7 @@
 					"2012-01-24T13:00:00-00:00": 19,
 					"2012-01-24T14:00:00-00:00": 13,
 					"2012-01-27T09:00:00-00:00": 23
-			},
+				},
 				"participations": [
 					{
 						"created_at": "2012-01-21T22:00:00-06:00",
@@ -1679,16 +1701,34 @@
 		"endpoint": "courses/1/analytics/users/1/communication",
 		"data": [
 			{
-				"2012-01-24":{
-					"instructorMessages":1,
-					"studentMessages":2
+				"2012-01-24": {
+					"instructorMessages": 1,
+					"studentMessages": 2
 				},
-				"2012-01-27":{
-					"studentMessages":1
+				"2012-01-27": {
+					"studentMessages": 1
 				}
 			}
 		]
 	},
+	"query_audit_by_course": {
+		"method": "GET",
+		"endpoint": "audit/course/courses/1",
+		"data": [
+			{
+				"id": 1,
+				"name": "FIU",
+				"start_at": "2022-11-18T05:00:00-06:00",
+				"conclude_at": "2022-11-18T15:00:00-06:00"
+			},
+			{
+				"id": 2,
+				"name": "UNF",
+				"start_at": "2022-11-18T05:00:00-06:00",
+				"conclude_at": "2022-11-18T15:00:00-06:00"
+			}
+		]
+	},
 	"list_tabs": {
 		"method": "GET",
 		"endpoint": "courses/1/tabs",
@@ -1796,12 +1836,12 @@
 		"method": "PUT",
 		"endpoint": "courses/1/assignments/1/submissions/1",
 		"data": {
-				"id": 1,
-				"assignments_id": 1,
-				"user_id": 1,
-				"html_url": "https://example.com/courses/1/assignments/1/submissions/1",
-				"submission_type": "online_upload",
-				"excused": true
+			"id": 1,
+			"assignments_id": 1,
+			"user_id": 1,
+			"html_url": "https://example.com/courses/1/assignments/1/submissions/1",
+			"submission_type": "online_upload",
+			"excused": true
 		},
 		"status_code": 200
 	},
@@ -1820,15 +1860,13 @@
 		"endpoint": "search/all_courses",
 		"data": [
 			{
-				"course":
-				{
+				"course": {
 					"id": 1,
 					"name": "Course 1"
 				}
 			},
 			{
-				"course":
-				{
+				"course": {
 					"id": 2,
 					"name": "Course 2"
 				}
@@ -1845,11 +1883,20 @@
 			"context_id": 1,
 			"context_type": "Course",
 			"grading_scheme": [
-			  {"name": "A", "value": 0.9},
-			  {"name": "B", "value": 0.8},
-			  {"name": "C", "value": 0.7}
+				{
+					"name": "A",
+					"value": 0.9
+				},
+				{
+					"name": "B",
+					"value": 0.8
+				},
+				{
+					"name": "C",
+					"value": 0.7
+				}
 			]
-		  },
+		},
 		"status_code": 200
 	},
 	"get_grading_periods": {
@@ -1890,26 +1937,41 @@
 		"endpoint": "courses/1/grading_standards",
 		"data": [
 			{
-			"title": "Grading Standard 1",
-			"id": 1,
-			"context_id": 1,
-			"context_type": "Course",
-			"grading_scheme": [
-			  {"name": "A", "value": 0.9},
-			  {"name": "B", "value": 0.8},
-			  {"name": "C", "value": 0.7}
-			]
-		  },
-		  {
-			"title": "Grading Standard 2",
-			"id": 2,
-			"context_id": 1,
-			"context_type": "Course",
-			"grading_scheme": [
-			  {"name": "D", "value": 0.6},
-			  {"name": "F", "value": 0.5}
-			]
-		  }
+				"title": "Grading Standard 1",
+				"id": 1,
+				"context_id": 1,
+				"context_type": "Course",
+				"grading_scheme": [
+					{
+						"name": "A",
+						"value": 0.9
+					},
+					{
+						"name": "B",
+						"value": 0.8
+					},
+					{
+						"name": "C",
+						"value": 0.7
+					}
+				]
+			},
+			{
+				"title": "Grading Standard 2",
+				"id": 2,
+				"context_id": 1,
+				"context_type": "Course",
+				"grading_scheme": [
+					{
+						"name": "D",
+						"value": 0.6
+					},
+					{
+						"name": "F",
+						"value": 0.5
+					}
+				]
+			}
 		],
 		"status_code": 200
 	},
@@ -1923,7 +1985,7 @@
 					{
 						"name": "John Smith",
 						"id": 49,
-						"assignments":[
+						"assignments": [
 							{
 								"id": 44,
 								"description": "<p>homework1</p>"
@@ -1938,7 +2000,7 @@
 					{
 						"name": "Sara Hanks",
 						"id": 32,
-						"assignments":[
+						"assignments": [
 							{
 								"id": 19,
 								"description": "<p>homework2</p>"
@@ -1948,7 +2010,6 @@
 				]
 			}
 		]
-
 	},
 	"get_gradebook_history_details": {
 		"method": "GET",
@@ -1957,12 +2018,20 @@
 			{
 				"id": 27,
 				"name": "John Smith",
-				"assignments": [1, 2, 3]
+				"assignments": [
+					1,
+					2,
+					3
+				]
 			},
 			{
 				"id": 30,
 				"name": "Jenny Parker",
-				"assignments": [4, 5, 6]
+				"assignments": [
+					4,
+					5,
+					6
+				]
 			}
 		]
 	},
@@ -1975,11 +2044,20 @@
 			"context_id": 1,
 			"context_type": "Course",
 			"grading_scheme": [
-			  {"name": "A", "value": 0.9},
-			  {"name": "B", "value": 0.8},
-			  {"name": "C", "value": 0.7}
+				{
+					"name": "A",
+					"value": 0.9
+				},
+				{
+					"name": "B",
+					"value": 0.8
+				},
+				{
+					"name": "C",
+					"value": 0.7
+				}
 			]
-		  },
+		},
 		"status_code": 200
 	},
 	"create_content_migration": {
@@ -2136,16 +2214,8 @@
 		"method": "GET",
 		"endpoint": "courses/1/features/enabled",
 		"data": [
-			{
-				"name": "feature_test",
-				"display_name": "Feature Test",
-				"applies_to": "Course"
-			},
-			{
-				"name": "feature_second",
-				"display_name": "Feature Second",
-				"applies_to": "Course"
-			}
+			"feature_one",
+			"feature_two"
 		],
 		"status_code": 200
 	},
@@ -2241,7 +2311,10 @@
 			"use_justification": "fair_use",
 			"license": "private",
 			"message": "2 files updated",
-			"file_ids": [1,2]
+			"file_ids": [
+				1,
+				2
+			]
 		},
 		"status_code": 200
 	},
@@ -2250,7 +2323,10 @@
 		"endpoint": "courses/1/usage_rights",
 		"data": {
 			"message": "2 files updated",
-			"file_ids": [1,2]
+			"file_ids": [
+				1,
+				2
+			]
 		},
 		"status_code": 200
 	},
@@ -2316,11 +2392,11 @@
 		],
 		"status_code": 200
 	},
-    "resolve_path": {
+	"resolve_path": {
 		"method": "GET",
 		"endpoint": "courses/1/folders/by_path/Folder_Level_1/Folder_Level_2/Folder_Level_3",
 		"data": [
-            {
+			{
 				"id": 2,
 				"files_count": 0,
 				"folders_count": 1,
@@ -2351,18 +2427,18 @@
 		],
 		"status_code": 200
 	},
-    "resolve_path_null": {
+	"resolve_path_null": {
 		"method": "GET",
 		"endpoint": "courses/1/folders/by_path",
 		"data": [
-            {
+			{
 				"id": 2,
 				"files_count": 0,
 				"folders_count": 1,
 				"name": "course_files",
 				"full_name": "course_files"
 			}
-        ],
+		],
 		"status_code": 200
 	}
 }
diff --git a/tests/fixtures/enrollment.json b/tests/fixtures/enrollment.json
index d665daf..c8b7527 100644
--- a/tests/fixtures/enrollment.json
+++ b/tests/fixtures/enrollment.json
@@ -33,5 +33,21 @@
 			"state": "active"
 		},
 		"status_code": 200
+	},
+	"accept": {
+		"method": "POST",
+		"endpoint": "courses/1/enrollments/1/accept",
+		"data": {
+			"success": true
+		},
+		"status_code": 200
+	},
+	"reject": {
+		"method": "POST",
+		"endpoint": "courses/1/enrollments/1/reject",
+		"data": {
+			"success": true
+		},
+		"status_code": 200
 	}
-}
\ No newline at end of file
+}
diff --git a/tests/fixtures/file.json b/tests/fixtures/file.json
index f5aa344..7d00713 100644
--- a/tests/fixtures/file.json
+++ b/tests/fixtures/file.json
@@ -32,5 +32,14 @@
         "endpoint": "ANY",
         "data": "file contents are here",
         "status_code": 200
+    },
+    "update_file": {
+        "method": "PUT",
+        "endpoint": "files/1",
+        "data": {
+            "id": 1,
+            "display_name": "New filename.docx"
+        },
+        "status_code": 200
     }
 }
diff --git a/tests/fixtures/jwt.json b/tests/fixtures/jwt.json
new file mode 100644
index 0000000..e4c414a
--- /dev/null
+++ b/tests/fixtures/jwt.json
@@ -0,0 +1,17 @@
+{
+  "create_jwt": {
+    "method": "POST",
+    "endpoint": "jwts",
+    "data": {
+      "token": "ZjM0UTZmLyVNSjdqb10wLV9jQSxeUiogXUlCWUs7Tg=="
+    }
+  },
+
+  "refresh_jwt": {
+    "method": "POST",
+    "endpoint": "jwts/refresh",
+    "data": {
+      "token": "O3MzNjpPKWc+fmFfMXRJJiEoR1VbSDVDT1IzUF1IJUpjJ3JSe0lrMHw8OUlX"
+    }
+  }
+}
diff --git a/tests/fixtures/rubric.json b/tests/fixtures/rubric.json
index df4e058..0eea19c 100644
--- a/tests/fixtures/rubric.json
+++ b/tests/fixtures/rubric.json
@@ -1,4 +1,64 @@
 {
+	"create_rubric_assessment": {
+		"method": "POST",
+		"endpoint": "courses/1/rubric_associations/4/rubric_assessments",
+		"data": {
+			"id": 1,
+			"rubric_id": 1,
+			"rubric_association_id": 4,
+			"score": 5.0,
+			"artifact_type": "Submission",
+			"artifact_id": 3,
+			"artifact_attempt": 2,
+			"assessment_type": "grading",
+			"assessor_id": 6,
+			"provisional": "false"
+		},
+		"status_code": 200
+	},
+	"update_rubric_assessment": {
+		"method": "PUT",
+		"endpoint": "courses/4/rubric_associations/4/rubric_assessments/1",
+		"data": {
+			"id": 1,
+			"rubric_id": 1,
+			"rubric_association_id": 4,
+			"score": 5.0,
+			"artifact_type": "Submission",
+			"artifact_id": 3,
+			"artifact_attempt": 2,
+			"assessment_type": "grading",
+			"assessor_id": 6,
+			"provisional": "true"
+		},
+		"status_code": 200
+	},
+	"delete_rubric_assessment": {
+		"method": "DELETE",
+		"endpoint": "courses/4/rubric_associations/4/rubric_assessments/1",
+		"data": {
+			"id": 1,
+			"rubric_id": 1,
+			"rubric_association_id": 4,
+			"score": 5.0,
+			"artifact_type": "Submission",
+			"artifact_id": 3,
+			"artifact_attempt": 2,
+			"assessment_type": "grading",
+			"assessor_id": 6,
+			"provisional": "false"
+		},
+		"status_code": 200
+	},
+	"create_rubric_association": {
+		"method": "POST",
+		"endpoint": "courses/1/rubric_associations/",
+		"data": {
+			"id": 5,
+			"association_type": "Assignment"
+		},
+		"status_code": 200
+	},
 	"update_rubric_association": {
 		"method": "PUT",
 		"endpoint": "courses/1/rubric_associations/4",
diff --git a/tests/fixtures/user.json b/tests/fixtures/user.json
index 557bf33..b3e6723 100644
--- a/tests/fixtures/user.json
+++ b/tests/fixtures/user.json
@@ -183,16 +183,16 @@
 		"status_code": 200
 	},
 	"create_folder": {
-        "method": "POST",
-        "endpoint": "users/1/folders",
-        "data": {
-            "id": 2,
-            "name": "Test String",
-            "locked": false,
-            "hidden": false
-        },
-        "status_code": 200
-    },
+		"method": "POST",
+		"endpoint": "users/1/folders",
+		"data": {
+			"id": 2,
+			"name": "Test String",
+			"locked": false,
+			"hidden": false
+		},
+		"status_code": 200
+	},
 	"edit": {
 		"method": "PUT",
 		"endpoint": "users/1",
@@ -243,39 +243,39 @@
 			"size": 1024
 		},
 		"status_code": 200
-    },
-    "get_file_quota": {
-        "method": "GET",
-        "endpoint": "users/1/files/quota",
-        "data": {
-            "quota": 889234510,
-            "quota_used": 476231098
-        },
-        "status_code": 200
-    },
+	},
+	"get_file_quota": {
+		"method": "GET",
+		"endpoint": "users/1/files/quota",
+		"data": {
+			"quota": 889234510,
+			"quota_used": 476231098
+		},
+		"status_code": 200
+	},
 	"get_folder": {
-        "method": "GET",
-        "endpoint": "users/1/folders/1",
-        "data": {
-            "id": 1,
-            "files_count": 10,
-            "folders_count": 2,
-            "name": "Folder 1",
-            "full_name": "Folder 1"
-        },
-        "status_code": 200
-    },
+		"method": "GET",
+		"endpoint": "users/1/folders/1",
+		"data": {
+			"id": 1,
+			"files_count": 10,
+			"folders_count": 2,
+			"name": "Folder 1",
+			"full_name": "Folder 1"
+		},
+		"status_code": 200
+	},
 	"get_folder_2": {
-        "method": "GET",
-        "endpoint": "users/1/folders/2",
-        "data": {
-            "id": 2,
-            "files_count": 10,
-            "folders_count": 2,
-            "name": "Folder 2",
-            "full_name": "Folder 1"
-        },
-        "status_code": 200
+		"method": "GET",
+		"endpoint": "users/1/folders/2",
+		"data": {
+			"id": 2,
+			"files_count": 10,
+			"folders_count": 2,
+			"name": "Folder 2",
+			"full_name": "Folder 1"
+		},
+		"status_code": 200
 	},
 	"observer_pairing_codes": {
 		"method": "POST",
@@ -479,26 +479,26 @@
 		"status_code": 200
 	},
 	"list_folders": {
-        "method": "GET",
-        "endpoint": "users/1/folders",
-        "data": [
-            {
-                "id": 2,
-                "files_count": 0,
-                "folders_count": 0,
-                "name": "Folder 2",
-                "full_name": "user_files/Folder 2"
-            },
-            {
-                "id": 3,
-                "files_count": 0,
-                "folders_count": 0,
-                "name": "Folder 3",
-                "full_name": "user_files/Folder 3"
-            }
-        ],
-        "status_code": 200
-    },
+		"method": "GET",
+		"endpoint": "users/1/folders",
+		"data": [
+			{
+				"id": 2,
+				"files_count": 0,
+				"folders_count": 0,
+				"name": "Folder 2",
+				"full_name": "user_files/Folder 2"
+			},
+			{
+				"id": 3,
+				"files_count": 0,
+				"folders_count": 0,
+				"name": "Folder 3",
+				"full_name": "user_files/Folder 3"
+			}
+		],
+		"status_code": 200
+	},
 	"merge": {
 		"method": "PUT",
 		"endpoint": "users/1/merge_into/2",
@@ -804,18 +804,22 @@
 		"method": "GET",
 		"endpoint": "search/recipients",
 		"data": [
-  			{
-  				"id": "group_1",
-  				"name": "the group",
-  				"type": "context",
-  				"user_count": 3
-  			},
-  			{
-  				"id": 2,
-  				"name": "greg",
-  				"common_courses": {},
-  				"common_groups": {"1": ["Member"]}
-  			}
+			{
+				"id": "group_1",
+				"name": "the group",
+				"type": "context",
+				"user_count": 3
+			},
+			{
+				"id": 2,
+				"name": "greg",
+				"common_courses": {},
+				"common_groups": {
+					"1": [
+						"Member"
+					]
+				}
+			}
 		],
 		"status_code": 200
 	},
@@ -915,7 +919,9 @@
 						"grading_type": "points",
 						"course_id": 1,
 						"name": "Test assignment",
-						"submission_types": ["online_text_entry"]
+						"submission_types": [
+							"online_text_entry"
+						]
 					}
 				],
 				"courses": [
@@ -996,7 +1002,9 @@
 						"grading_type": "points",
 						"course_id": 1,
 						"name": "Test assignment",
-						"submission_types": ["online_text_entry"]
+						"submission_types": [
+							"online_text_entry"
+						]
 					}
 				],
 				"courses": [
@@ -1132,16 +1140,8 @@
 		"method": "GET",
 		"endpoint": "users/1/features/enabled",
 		"data": [
-			{
-				"name": "feature_one",
-				"display_name": "Feature One",
-				"applies_to": "User"
-			},
-			{
-				"name": "feature_two",
-				"display_name": "Feature Two",
-				"applies_to": "User"
-			}
+			"feature_one",
+			"feature_two"
 		],
 		"status_code": 200
 	},
@@ -1196,7 +1196,10 @@
 			"use_justification": "fair_use",
 			"license": "private",
 			"message": "2 files updated",
-			"file_ids": [1,2]
+			"file_ids": [
+				1,
+				2
+			]
 		},
 		"status_code": 200
 	},
@@ -1205,7 +1208,10 @@
 		"endpoint": "users/1/usage_rights",
 		"data": {
 			"message": "2 files updated",
-			"file_ids": [1,2]
+			"file_ids": [
+				1,
+				2
+			]
 		},
 		"status_code": 200
 	},
@@ -1226,11 +1232,11 @@
 		],
 		"status_code": 200
 	},
-    "resolve_path": {
+	"resolve_path": {
 		"method": "GET",
 		"endpoint": "users/1/folders/by_path/Folder_Level_1/Folder_Level_2/Folder_Level_3",
 		"data": [
-            {
+			{
 				"id": 2,
 				"files_count": 0,
 				"folders_count": 1,
@@ -1261,18 +1267,24 @@
 		],
 		"status_code": 200
 	},
-    "resolve_path_null": {
+	"resolve_path_null": {
 		"method": "GET",
 		"endpoint": "users/1/folders/by_path",
 		"data": [
-            {
+			{
 				"id": 2,
 				"files_count": 0,
 				"folders_count": 1,
 				"name": "my_files",
 				"full_name": "my_files"
 			}
-        ],
+		],
+		"status_code": 200
+	},
+	"terminate_sessions": {
+		"method": "DELETE",
+		"endpoint": "users/1/sessions",
+		"data": "ok",
 		"status_code": 200
 	}
 }
diff --git a/tests/test_account.py b/tests/test_account.py
index ab23f0a..9a0d04e 100644
--- a/tests/test_account.py
+++ b/tests/test_account.py
@@ -13,10 +13,12 @@ from canvasapi.account import (
     Role,
     SSOSettings,
 )
+from canvasapi.account_calendar import AccountCalendar
 from canvasapi.authentication_event import AuthenticationEvent
 from canvasapi.authentication_provider import AuthenticationProvider
 from canvasapi.content_migration import ContentMigration, Migrator
 from canvasapi.course import Course
+from canvasapi.course_event import CourseEvent
 from canvasapi.enrollment import Enrollment
 from canvasapi.enrollment_term import EnrollmentTerm
 from canvasapi.exceptions import CanvasException, RequiredFieldMissing
@@ -291,6 +293,39 @@ class TestAccount(unittest.TestCase):
         self.assertTrue(hasattr(report, "status"))
         self.assertEqual(report.status, "deleted")
 
+    # get account calendar
+    def test_get_account_calendar(self, m):
+        register_uris({"account": ["get_account_calendar"]}, m)
+
+        # Check object is of type AccountCalendar
+        account_calendar = self.account.get_account_calendar()
+        self.assertIsInstance(account_calendar, AccountCalendar)
+
+        # Verify contents of object
+        self.assertEqual(account_calendar.id, 10)
+        self.assertEqual(account_calendar.name, "Department of Computer Science")
+
+    # get all account calendars
+    def test_get_all_account_calendars(self, m):
+        register_uris({"account": ["get_all_account_calendars"]}, m)
+
+        # Get paginated list and convert to list
+        account_calendars = self.account.get_all_account_calendars()
+        account_calendars_list = list(account_calendars)
+
+        # Check that list contains objects of type AccountCalendar
+        self.assertEqual(len(account_calendars_list), 2)
+        self.assertIsInstance(account_calendars_list[0], AccountCalendar)
+        self.assertIsInstance(account_calendars_list[1], AccountCalendar)
+
+        # Verify contents of first object
+        self.assertEqual(account_calendars_list[0].id, 1)
+        self.assertEqual(account_calendars_list[0].name, "FSU")
+
+        # Verify contents of second object
+        self.assertEqual(account_calendars_list[1].id, 2)
+        self.assertEqual(account_calendars_list[1].name, "Full Sail")
+
     # get_report
     def test_get_report(self, m):
         required = {"account": ["get_report"]}
@@ -328,6 +363,27 @@ class TestAccount(unittest.TestCase):
         self.assertTrue(hasattr(reports_list[0], "id"))
         self.assertIsInstance(str(reports_list[0]), str)
 
+    # get query by account
+    def test_query_audit_by_account(self, m):
+        register_uris({"account": ["query_audit_by_account"]}, m)
+
+        # Get paginated list and convert to list
+        query = self.account.query_audit_by_account()
+        query_list = list(query)
+
+        # Check that list contains objects of type CourseEvent
+        self.assertEqual(len(query_list), 2)
+        self.assertIsInstance(query_list[0], CourseEvent)
+        self.assertIsInstance(query_list[1], CourseEvent)
+
+        # Verify contents of first object
+        self.assertEqual(query_list[0].id, 1)
+        self.assertEqual(query_list[0].name, "UCF")
+
+        # Verify contents of second object
+        self.assertEqual(query_list[1].id, 2)
+        self.assertEqual(query_list[1].name, "FSU")
+
     # get_subaccounts()
     def test_get_subaccounts(self, m):
         required = {"account": ["subaccounts", "subaccounts_page_2"]}
@@ -1123,7 +1179,6 @@ class TestAccount(unittest.TestCase):
         self.assertEqual(outcome_import.data["import_type"], "instructure_csv")
 
     def test_import_outcome_id(self, m):
-
         register_uris({"account": ["import_outcome"]}, m)
 
         outcome_import = self.account.import_outcome(1)
@@ -1224,6 +1279,32 @@ class TestAccount(unittest.TestCase):
         self.assertTrue(hasattr(updated_notif, "subject"))
         self.assertEqual(updated_notif.subject, "subject")
 
+    # update account calendar visibility
+    def test_update_account_calendar_visibility(self, m):
+        register_uris({"account": ["update_account_calendar_visibility"]}, m)
+
+        # verify object is of type AccountCalendar
+        account_calendar = self.account.update_account_calendar_visibility()
+        self.assertIsInstance(account_calendar, AccountCalendar)
+
+        # verify contents of object
+        self.assertEqual(account_calendar.id, 102)
+        self.assertEqual(account_calendar.name, "Department of Aerospace Engineering")
+        self.assertTrue(account_calendar.visible)
+
+    # update many account calendars' visibility
+    def test_update_many_account_calendars_visibility(self, m):
+        register_uris({"account": ["update_many_account_calendars_visibility"]}, m)
+
+        # verify the returned object is of type AccountCalendar
+        account_calendar = self.account.update_many_account_calendars_visibility()
+        self.assertIsInstance(account_calendar, AccountCalendar)
+
+        # Verify contents of object
+        self.assertEqual(account_calendar.id, 1)
+        self.assertEqual(account_calendar.name, "Biology Department")
+        self.assertTrue(account_calendar.visible)
+
     def test_update_global_notification_missing_field(self, m):
         register_uris({"account": ["update_notification"]}, m)
 
@@ -1335,8 +1416,8 @@ class TestAccountReport(unittest.TestCase):
 
         features = self.account.get_enabled_features()
 
-        self.assertIsInstance(features, PaginatedList)
-        self.assertIsInstance(features[0], Feature)
+        self.assertIsInstance(features, list)
+        self.assertIsInstance(features[0], str)
 
     # get_feature_flag()
     def test_get_feature_flag(self, m):
diff --git a/tests/test_account_calendar.py b/tests/test_account_calendar.py
new file mode 100644
index 0000000..a660f92
--- /dev/null
+++ b/tests/test_account_calendar.py
@@ -0,0 +1,24 @@
+import unittest
+
+import requests_mock
+
+from canvasapi import Canvas
+from tests import settings
+from tests.util import register_uris
+
+
+@requests_mock.Mocker()
+class TestAccountCalendar(unittest.TestCase):
+    def setUp(self):
+        self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
+
+        with requests_mock.Mocker() as m:
+            register_uris({"account": ["get_account_calendar", "get_by_id"]}, m)
+
+            self.account = self.canvas.get_account(1)
+            self.account_calendar = self.account.get_account_calendar()
+
+    # __str__()
+    def test__str__(self, m):
+        string = str(self.account_calendar)
+        self.assertIsInstance(string, str)
diff --git a/tests/test_assignment.py b/tests/test_assignment.py
index 28f36de..8f59ac8 100644
--- a/tests/test_assignment.py
+++ b/tests/test_assignment.py
@@ -17,7 +17,7 @@ from canvasapi.paginated_list import PaginatedList
 from canvasapi.peer_review import PeerReview
 from canvasapi.progress import Progress
 from canvasapi.submission import Submission
-from canvasapi.user import UserDisplay
+from canvasapi.user import User, UserDisplay
 from tests import settings
 from tests.util import cleanup_file, register_uris
 
@@ -137,6 +137,16 @@ class TestAssignment(unittest.TestCase):
         self.assertEqual(len(peer_review_list), 2)
         self.assertIsInstance(peer_review_list[0], PeerReview)
 
+    # get_students_selected_for_moderation()
+    def test_get_students_selected_for_moderation(self, m):
+        register_uris({"assignment": ["get_students_selected_moderation"]}, m)
+
+        selected_students = self.assignment.get_students_selected_for_moderation()
+        selected_student_list = list(selected_students)
+
+        self.assertEqual(len(selected_student_list), 2)
+        self.assertIsInstance(selected_student_list[0], User)
+
     # get_submission()
     def test_get_submission(self, m):
         register_uris({"submission": ["get_by_id_course"], "user": ["get_by_id"]}, m)
@@ -333,6 +343,18 @@ class TestAssignment(unittest.TestCase):
         self.assertIsInstance(status, bool)
         self.assertFalse(status)
 
+    # select_students_for_moderation()
+    def test_select_students_for_moderation(self, m):
+        register_uris({"assignment": ["select_students_for_moderation"]}, m)
+
+        selected_students = self.assignment.select_students_for_moderation(
+            student_ids=[11, 12]
+        )
+        selected_student_list = list(selected_students)
+
+        self.assertEqual(len(selected_student_list), 2)
+        self.assertIsInstance(selected_student_list[0], User)
+
     # selected_provisional_grade
     def test_selected_provisional_grade(self, m):
         register_uris({"assignment": ["selected_provisional_grade"]}, m)
diff --git a/tests/test_canvas.py b/tests/test_canvas.py
index 35ece62..8533565 100644
--- a/tests/test_canvas.py
+++ b/tests/test_canvas.py
@@ -7,6 +7,7 @@ import requests_mock
 
 from canvasapi import Canvas
 from canvasapi.account import Account
+from canvasapi.account_calendar import AccountCalendar
 from canvasapi.appointment_group import AppointmentGroup
 from canvasapi.calendar_event import CalendarEvent
 from canvasapi.comm_message import CommMessage
@@ -18,6 +19,7 @@ from canvasapi.eportfolio import EPortfolio
 from canvasapi.exceptions import RequiredFieldMissing, ResourceDoesNotExist
 from canvasapi.file import File
 from canvasapi.group import Group, GroupCategory
+from canvasapi.jwt import JWT
 from canvasapi.outcome import Outcome, OutcomeGroup
 from canvasapi.paginated_list import PaginatedList
 from canvasapi.poll import Poll
@@ -95,6 +97,47 @@ class TestCanvas(unittest.TestCase):
         self.assertTrue(hasattr(account, "name"))
         self.assertEqual(account.name, name)
 
+    # test token creation
+    def test_create_jwt(self, m):
+        register_uris({"jwt": ["create_jwt"]}, m)
+
+        # verify returned object is of type JWT
+        jwt = self.canvas.create_jwt()
+        self.assertIsInstance(jwt, JWT)
+
+        # check the token is correct and we received the right object
+        self.assertEqual(jwt.token, "ZjM0UTZmLyVNSjdqb10wLV9jQSxeUiogXUlCWUs7Tg==")
+
+    # refresh token
+    def test_refresh_jwt_str(self, m):
+        register_uris({"jwt": ["refresh_jwt"]}, m)
+
+        old_token = "ZjM0UTZmLyVNSjdqb10wLV9jQSxeUiogXUlCWUs7Tg=="
+        new_token = "O3MzNjpPKWc+fmFfMXRJJiEoR1VbSDVDT1IzUF1IJUpjJ3JSe0lrMHw8OUlX"
+
+        # verify returned object is of type JWT
+        jwt = self.canvas.refresh_jwt(jwt=old_token)
+        self.assertIsInstance(jwt, JWT)
+
+        # check the token is correct and we received the right object
+        self.assertEqual(jwt.token, new_token)
+
+    def test_refresh_jwt_obj(self, m):
+        register_uris({"jwt": ["create_jwt", "refresh_jwt"]}, m)
+
+        old_token = "ZjM0UTZmLyVNSjdqb10wLV9jQSxeUiogXUlCWUs7Tg=="
+        new_token = "O3MzNjpPKWc+fmFfMXRJJiEoR1VbSDVDT1IzUF1IJUpjJ3JSe0lrMHw8OUlX"
+
+        old_jwt = self.canvas.create_jwt()
+        self.assertEqual(old_jwt.token, old_token)
+
+        # verify returned object is of type JWT
+        jwt = self.canvas.refresh_jwt(jwt=old_jwt)
+        self.assertIsInstance(jwt, JWT)
+
+        # check the token is correct and we received the right object
+        self.assertEqual(jwt.token, new_token)
+
     # create_poll()
     def test_create_poll(self, m):
         register_uris({"poll": ["create_poll"]}, m)
@@ -124,6 +167,26 @@ class TestCanvas(unittest.TestCase):
         account_by_obj = self.canvas.get_account(account_by_id)
         self.assertIsInstance(account_by_obj, Account)
 
+    # get account calendars
+    def test_get_account_calendars(self, m):
+        register_uris({"account": ["get_account_calendars"]}, m)
+
+        # Convert to list for further testing
+        account_calendars = self.canvas.get_account_calendars()
+        account_calendars_list = list(account_calendars)
+
+        # Check that list contains objects of type AccountCalendar
+        self.assertEqual(len(account_calendars_list), 2)
+        self.assertIsInstance(account_calendars_list[0], AccountCalendar)
+
+        # Verify contents of first object
+        self.assertEqual(account_calendars_list[0].id, 1)
+        self.assertEqual(account_calendars_list[0].name, "CDL")
+
+        # Verify contents of second object
+        self.assertEqual(account_calendars_list[1].id, 2)
+        self.assertEqual(account_calendars_list[1].name, "DDL")
+
     def test_get_account_sis_id(self, m):
         register_uris({"account": ["get_by_sis_id"]}, m)
 
@@ -791,7 +854,6 @@ class TestCanvas(unittest.TestCase):
 
     # get_epub_exports()
     def test_get_epub_exports(self, m):
-
         register_uris({"course": ["get_epub_exports"]}, m)
 
         epub_export_list = self.canvas.get_epub_exports()
diff --git a/tests/test_course.py b/tests/test_course.py
index b9a3dae..21b483b 100644
--- a/tests/test_course.py
+++ b/tests/test_course.py
@@ -13,6 +13,7 @@ from canvasapi.content_export import ContentExport
 from canvasapi.content_migration import ContentMigration, Migrator
 from canvasapi.course import Course, CourseNickname, LatePolicy, Page
 from canvasapi.course_epub_export import CourseEpubExport
+from canvasapi.course_event import CourseEvent
 from canvasapi.custom_gradebook_columns import CustomGradebookColumn
 from canvasapi.discussion_topic import DiscussionTopic
 from canvasapi.enrollment import Enrollment
@@ -753,6 +754,27 @@ class TestCourse(unittest.TestCase):
         self.assertTrue(hasattr(discussion_by_obj, "course_id"))
         self.assertEqual(discussion_by_obj.course_id, 1)
 
+    # get query by course
+    def test_query_audit_by_course(self, m):
+        register_uris({"course": ["query_audit_by_course"]}, m)
+
+        # Get paginated list and convert to list
+        query = self.course.query_audit_by_course()
+        query_list = list(query)
+
+        # Check that list contains objects of type CourseEvent
+        self.assertEqual(len(query_list), 2)
+        self.assertIsInstance(query_list[0], CourseEvent)
+        self.assertIsInstance(query_list[1], CourseEvent)
+
+        # Verify contents of first object
+        self.assertEqual(query_list[0].id, 1)
+        self.assertEqual(query_list[0].name, "FIU")
+
+        # Verify contents of second object
+        self.assertEqual(query_list[1].id, 2)
+        self.assertEqual(query_list[1].name, "UNF")
+
     # get_file()
     def test_get_file(self, m):
         register_uris({"course": ["get_file"]}, m)
@@ -1542,7 +1564,6 @@ class TestCourse(unittest.TestCase):
         self.assertEqual(outcome_import.data["import_type"], "instructure_csv")
 
     def test_import_outcome_id(self, m):
-
         register_uris({"course": ["import_outcome"]}, m)
 
         outcome_import = self.course.import_outcome(1)
@@ -1666,8 +1687,8 @@ class TestCourse(unittest.TestCase):
 
         enabled_features = self.course.get_enabled_features()
 
-        self.assertIsInstance(enabled_features, PaginatedList)
-        self.assertIsInstance(enabled_features[0], Feature)
+        self.assertIsInstance(enabled_features, list)
+        self.assertIsInstance(enabled_features[0], str)
 
     # get_feature_flag()
     def test_get_feature_flag(self, m):
diff --git a/tests/test_course_event.py b/tests/test_course_event.py
new file mode 100644
index 0000000..0c593b4
--- /dev/null
+++ b/tests/test_course_event.py
@@ -0,0 +1,30 @@
+import unittest
+
+import requests_mock
+
+from canvasapi import Canvas
+from tests import settings
+from tests.util import register_uris
+
+
+@requests_mock.Mocker()
+class TestCourseEvent(unittest.TestCase):
+    def setUp(self):
+        self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
+
+        with requests_mock.Mocker() as m:
+            requires = {
+                "account": ["get_by_id", "query_audit_by_account"],
+                "course": ["query_audit_by_course"],
+            }
+            register_uris(requires, m)
+
+            self.account = self.canvas.get_account(1)
+
+            # isolate one of the CourseEvent objects
+            self.query_audit_by_account = self.account.query_audit_by_account()[0]
+
+    # __str__()
+    def test__str__(self, m):
+        string = str(self.query_audit_by_account)
+        self.assertIsInstance(string, str)
diff --git a/tests/test_enrollment.py b/tests/test_enrollment.py
index 111cf5d..17b7616 100644
--- a/tests/test_enrollment.py
+++ b/tests/test_enrollment.py
@@ -44,3 +44,21 @@ class TestEnrollment(unittest.TestCase):
         target_enrollment = self.enrollment.reactivate()
 
         self.assertIsInstance(target_enrollment, Enrollment)
+
+    # accept()
+    def test_accept(self, m):
+        register_uris({"enrollment": ["accept"]}, m)
+
+        enrollment_accepted = self.enrollment.accept()
+
+        self.assertIsInstance(enrollment_accepted, bool)
+        self.assertTrue(enrollment_accepted)
+
+    # reject()
+    def test_reject(self, m):
+        register_uris({"enrollment": ["reject"]}, m)
+
+        enrollment_rejected = self.enrollment.reject()
+
+        self.assertIsInstance(enrollment_rejected, bool)
+        self.assertTrue(enrollment_rejected)
diff --git a/tests/test_favorite.py b/tests/test_favorite.py
index 6b30759..05b6cb9 100644
--- a/tests/test_favorite.py
+++ b/tests/test_favorite.py
@@ -25,7 +25,6 @@ class TestFavorite(unittest.TestCase):
 
     # __str__()
     def test_uncapitalized___str__(self, m):
-
         register_uris(
             {
                 "current_user": [
@@ -46,7 +45,6 @@ class TestFavorite(unittest.TestCase):
         self.assertIsInstance(string, str)
 
     def test_capitalized___str__(self, m):
-
         register_uris(
             {
                 "current_user": [
@@ -68,7 +66,6 @@ class TestFavorite(unittest.TestCase):
 
     # remove()
     def test_remove_uncapitalized_favorite_course(self, m):
-
         register_uris(
             {
                 "current_user": [
@@ -88,7 +85,6 @@ class TestFavorite(unittest.TestCase):
         self.assertEqual(evnt.context_id, 1)
 
     def test_remove_uncapitalized_favorite_group(self, m):
-
         register_uris(
             {
                 "current_user": [
@@ -108,7 +104,6 @@ class TestFavorite(unittest.TestCase):
         self.assertEqual(evnt.context_id, 1)
 
     def test_remove_capitalized_favorite_course(self, m):
-
         register_uris(
             {
                 "current_user": [
@@ -128,7 +123,6 @@ class TestFavorite(unittest.TestCase):
         self.assertEqual(evnt.context_id, 1)
 
     def test_remove_capitalized_favorite_group(self, m):
-
         register_uris(
             {
                 "current_user": [
diff --git a/tests/test_file.py b/tests/test_file.py
index ed7a569..543ca8a 100644
--- a/tests/test_file.py
+++ b/tests/test_file.py
@@ -55,3 +55,13 @@ class TestFile(unittest.TestCase):
         self.assertEqual(contents, '"Hello there"')
         contents_binary = self.file.get_contents(binary=True)
         self.assertEqual(contents_binary, b'"Hello there"')
+
+    # update()
+    def test_update_file(self, m):
+        register_uris({"file": ["update_file"]}, m)
+
+        updated_file = self.file.update(name="New filename.docx")
+
+        self.assertIsInstance(updated_file, File)
+        self.assertTrue(hasattr(updated_file, "display_name"))
+        self.assertEqual(updated_file.display_name, "New filename.docx")
diff --git a/tests/test_gradebook_history.py b/tests/test_gradebook_history.py
index 6ccf40b..00bfcce 100644
--- a/tests/test_gradebook_history.py
+++ b/tests/test_gradebook_history.py
@@ -10,7 +10,6 @@ from tests.util import register_uris
 @requests_mock.Mocker()
 class TestDay(unittest.TestCase):
     def setUp(self):
-
         self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
 
         with requests_mock.Mocker() as m:
@@ -29,7 +28,6 @@ class TestDay(unittest.TestCase):
 @requests_mock.Mocker()
 class TestGrader(unittest.TestCase):
     def setUp(self):
-
         self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
 
         with requests_mock.Mocker() as m:
@@ -50,7 +48,6 @@ class TestGrader(unittest.TestCase):
 @requests_mock.Mocker()
 class TestSubmissionHistory(unittest.TestCase):
     def setUp(self):
-
         self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
 
         with requests_mock.Mocker() as m:
@@ -71,7 +68,6 @@ class TestSubmissionHistory(unittest.TestCase):
 @requests_mock.Mocker()
 class TestSubmissionVersion(unittest.TestCase):
     def setUp(self):
-
         self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
 
         with requests_mock.Mocker() as m:
diff --git a/tests/test_grading_period.py b/tests/test_grading_period.py
index 8a76fcf..218c69e 100644
--- a/tests/test_grading_period.py
+++ b/tests/test_grading_period.py
@@ -20,7 +20,6 @@ class TestGradingPeriod(unittest.TestCase):
         )
 
     def test_str(self, m):
-
         test_str = str(self.grading_period)
         self.assertIsInstance(test_str, str)
 
diff --git a/tests/test_jwt.py b/tests/test_jwt.py
new file mode 100644
index 0000000..f6e8127
--- /dev/null
+++ b/tests/test_jwt.py
@@ -0,0 +1,23 @@
+import unittest
+
+import requests_mock
+
+from canvasapi import Canvas
+from tests import settings
+from tests.util import register_uris
+
+
+@requests_mock.Mocker()
+class TestJWT(unittest.TestCase):
+    def setUp(self):
+        self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
+
+        with requests_mock.Mocker() as m:
+            register_uris({"jwt": ["create_jwt"]}, m)
+
+            self.jwt = self.canvas.create_jwt()
+
+    # __str__()
+    def test__str__(self, m):
+        string = str(self.jwt)
+        self.assertIsInstance(string, str)
diff --git a/tests/test_outcome_import.py b/tests/test_outcome_import.py
index 1222ea0..3b563cb 100644
--- a/tests/test_outcome_import.py
+++ b/tests/test_outcome_import.py
@@ -17,6 +17,5 @@ class TestOutcomeImport(unittest.TestCase):
         )
 
     def test_str(self, m):
-
         test_str = str(self.outcome_import)
         self.assertIsInstance(test_str, str)
diff --git a/tests/test_page.py b/tests/test_page.py
index 08e3b38..01ac166 100644
--- a/tests/test_page.py
+++ b/tests/test_page.py
@@ -13,7 +13,6 @@ from tests.util import register_uris
 @requests_mock.Mocker()
 class TestPage(unittest.TestCase):
     def setUp(self):
-
         self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
 
         with requests_mock.Mocker() as m:
diff --git a/tests/test_rubric.py b/tests/test_rubric.py
index 6735225..90c09b7 100644
--- a/tests/test_rubric.py
+++ b/tests/test_rubric.py
@@ -3,7 +3,7 @@ import unittest
 import requests_mock
 
 from canvasapi import Canvas
-from canvasapi.rubric import Rubric, RubricAssociation
+from canvasapi.rubric import Rubric, RubricAssessment, RubricAssociation
 from tests import settings
 from tests.util import register_uris
 
@@ -59,6 +59,52 @@ class TestGradingStandard(unittest.TestCase):
         self.assertIsInstance(string, str)
 
 
+@requests_mock.Mocker()
+class TestRubricAssessment(unittest.TestCase):
+    def setUp(self):
+        self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
+
+        with requests_mock.Mocker() as m:
+            register_uris(
+                {
+                    "course": [
+                        "get_by_id",
+                        "create_rubric_with_association",
+                        "create_rubric_association",
+                    ],
+                    "rubric": ["create_rubric_assessment"],
+                },
+                m,
+            )
+
+            self.course = self.canvas.get_course(1)
+            self.rubric = self.course.create_rubric()
+            self.association = self.course.create_rubric_association()
+            self.assessment = self.association.create_rubric_assessment()
+
+    def test__str__(self, m):
+        string = str(self.assessment)
+        self.assertIsInstance(string, str)
+
+    def test_update(self, m):
+        register_uris({"rubric": ["update_rubric_assessment"]}, m)
+
+        self.assertEqual(self.assessment.provisional, "false")
+
+        updated_assessment = self.assessment.update(provisional=True)
+
+        self.assertEqual(updated_assessment.id, 1)
+        self.assertEqual(updated_assessment.provisional, "true")
+
+    def test_delete(self, m):
+        register_uris({"rubric": ["delete_rubric_assessment"]}, m)
+
+        deleted_assessment = self.assessment.delete()
+
+        self.assertEqual(deleted_assessment.id, 1)
+        self.assertIsInstance(deleted_assessment, RubricAssessment)
+
+
 @requests_mock.Mocker()
 class TestRubricAssociation(unittest.TestCase):
     def setUp(self):
diff --git a/tests/test_scope.py b/tests/test_scope.py
index 2e7b1c4..aea5604 100644
--- a/tests/test_scope.py
+++ b/tests/test_scope.py
@@ -17,6 +17,5 @@ class TestGradingPeriod(unittest.TestCase):
         )
 
     def test_str(self, m):
-
         test_str = str(self.scope)
         self.assertIsInstance(test_str, str)
diff --git a/tests/test_submission.py b/tests/test_submission.py
index cdcb595..84b7a2d 100644
--- a/tests/test_submission.py
+++ b/tests/test_submission.py
@@ -14,7 +14,6 @@ from tests.util import cleanup_file, register_uris
 @requests_mock.Mocker()
 class TestSubmission(unittest.TestCase):
     def setUp(self):
-
         self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
 
         with requests_mock.Mocker() as m:
diff --git a/tests/test_user.py b/tests/test_user.py
index 9093b78..84a8b04 100644
--- a/tests/test_user.py
+++ b/tests/test_user.py
@@ -32,7 +32,6 @@ from tests.util import cleanup_file, register_uris
 @requests_mock.Mocker()
 class TestUser(unittest.TestCase):
     def setUp(self):
-
         self.canvas = Canvas(settings.BASE_URL, settings.API_KEY)
 
         with requests_mock.Mocker() as m:
@@ -551,8 +550,8 @@ class TestUser(unittest.TestCase):
 
         features = self.user.get_enabled_features()
 
-        self.assertIsInstance(features, PaginatedList)
-        self.assertIsInstance(features[0], Feature)
+        self.assertIsInstance(features, list)
+        self.assertIsInstance(features[0], str)
 
     # get_feature_flag()
     def test_get_feature_flag(self, m):
@@ -657,6 +656,12 @@ class TestUser(unittest.TestCase):
         self.assertIsInstance(pairing_code, PairingCode)
         self.assertEqual("abc123", pairing_code.code)
 
+    # terminate_sessions()
+    def test_terminate_sessions(self, m):
+        register_uris({"user": ["terminate_sessions"]}, m)
+        resp = self.user.terminate_sessions()
+        self.assertEqual(resp, "ok")
+
 
 @requests_mock.Mocker()
 class TestUserDisplay(unittest.TestCase):
diff --git a/tests/test_util.py b/tests/test_util.py
index 863d7e1..cd85648 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -92,7 +92,6 @@ class TestUtil(unittest.TestCase):
 
     # combine_kwargs()
     def test_combine_kwargs_empty(self, m):
-
         result = combine_kwargs()
         self.assertIsInstance(result, list)
         self.assertEqual(len(result), 0)
diff --git a/tests_requirements.txt b/tests_requirements.txt
index 3901ade..2eeab8b 100644
--- a/tests_requirements.txt
+++ b/tests_requirements.txt
@@ -1,6 +1,6 @@
 -r requirements.txt
 
-black
+black>=23.3.0
 coverage
 flake8
 isort