Repository: ucfopen/canvasapi (language: python)

Issue:
Account Calendars
**What resource needs additional coverage?**
Account Calendars

**What endpoints need to be covered?**

- [ ] [List available account calendars](https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.index)
- [ ] [Get a single account calendar](https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.show)
- [ ] [Update a calendar's visibility](https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.update)
- [ ] [Update many calendars' visibility](https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.bulk_update)
- [ ] [List all account calendars](https://canvas.instructure.com/doc/api/account_calendars.html#method.account_calendars_api.all_calendars)


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f82277a6..33a8df4c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
 
 ## [Unreleased]
 
+### 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
+
 ### General
 
 - Updated Codecov action to v3
diff --git a/canvasapi/account.py b/canvasapi/account.py
index 46d4f941..e9897dab 100644
--- a/canvasapi/account.py
+++ b/canvasapi/account.py
@@ -1,3 +1,4 @@
+from canvasapi.account_calendar import AccountCalendar
 from canvasapi.authentication_event import AuthenticationEvent
 from canvasapi.authentication_provider import AuthenticationProvider
 from canvasapi.canvas_object import CanvasObject
@@ -611,6 +612,24 @@ def delete_user(self, user, **kwargs):
         )
         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.
@@ -629,6 +648,25 @@ def get_admins(self, **kwargs):
             _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
@@ -1704,6 +1742,40 @@ def update_account_auth_settings(self, **kwargs):
 
         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.
diff --git a/canvasapi/account_calendar.py b/canvasapi/account_calendar.py
new file mode 100644
index 00000000..3ae3e535
--- /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/canvas.py b/canvasapi/canvas.py
index c90ae7de..3ae0a7e9 100644
--- a/canvasapi/canvas.py
+++ b/canvasapi/canvas.py
@@ -1,6 +1,7 @@
 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
@@ -394,6 +395,24 @@ def get_account(self, account, use_sis_id=False, **kwargs):
         )
         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.
diff --git a/docs/account-calendar-ref.rst b/docs/account-calendar-ref.rst
new file mode 100644
index 00000000..4e213f49
--- /dev/null
+++ b/docs/account-calendar-ref.rst
@@ -0,0 +1,6 @@
+===============
+AccountCalendar
+===============
+
+.. autoclass:: canvasapi.account_calendar.AccountCalendar
+    :members:
diff --git a/docs/class-reference.rst b/docs/class-reference.rst
index 21c0f2c7..765ac5f9 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


Test patch:
diff --git a/tests/fixtures/account.json b/tests/fixtures/account.json
index a9feaeff..84cdad01 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",
@@ -458,9 +525,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 +542,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 +559,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 +847,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 +939,7 @@
 	"create_role": {
 		"method": "POST",
 		"endpoint": "accounts/1/roles",
-		"data":{
+		"data": {
 			"id": 1,
 			"role": "StudentEnrollment",
 			"label": "Student"
@@ -1030,22 +1097,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 +1121,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 +1145,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 +1252,7 @@
 	"add_authentication_providers": {
 		"method": "POST",
 		"endpoint": "accounts/1/authentication_providers",
-		"data":{
+		"data": {
 			"id": 1,
 			"auth_type": "saml",
 			"position": 1
@@ -1227,11 +1294,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 +1315,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 +1415,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 +1763,7 @@
 	"abort_sis_imports_pending_blank": {
 		"method": "PUT",
 		"endpoint": "accounts/1/sis_imports/abort_all_pending",
-		"data": {
-		},
+		"data": {},
 		"status_code": 200
 	},
 	"create_admin": {
diff --git a/tests/test_account.py b/tests/test_account.py
index ab23f0ac..7717634d 100644
--- a/tests/test_account.py
+++ b/tests/test_account.py
@@ -13,6 +13,7 @@
     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
@@ -291,6 +292,39 @@ def test_delete_report(self, m):
         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"]}
@@ -1224,6 +1258,32 @@ def test_update_global_notification(self, m):
         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)
 
diff --git a/tests/test_account_calendar.py b/tests/test_account_calendar.py
new file mode 100644
index 00000000..a660f92a
--- /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_canvas.py b/tests/test_canvas.py
index 35ece62b..1cec0d11 100644
--- a/tests/test_canvas.py
+++ b/tests/test_canvas.py
@@ -7,6 +7,7 @@
 
 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
@@ -124,6 +125,26 @@ def test_get_account(self, m):
         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)