From b0d555ab15a709e36805fb06e99410dd6e1bb513 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Fri, 16 Jun 2017 15:15:25 -0400 Subject: [PATCH 01/10] Updated deploy procedures. Fixed capitalization in documentation title --- DEPLOY.md | 19 ++++++++++++++----- docs/index.rst | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index 2126063a..e4e197be 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -1,12 +1,13 @@ -canvasapi Deploy Procedures -========================== +CanvasAPI Deploy Procedures +=========================== Pre-Flight Checklist -------------------- -- On branch `master` and up-to-date +- On branch `develop` and up-to-date - All tests pass - 100% coverage +- No linter errors - `CHANGELOG` is accurate Packaging @@ -16,20 +17,28 @@ Update version number in `__init__.py`. Run `python setup.py sdist`. This should create a file in the `dist` directory called something like `canvasapi-0.0.0.tar.gz`. + Generate Documentation ---------------------- In the `docs` directory, run `make clean html`. -**TODO:** how to publish documentation. +This will create all the documentation files in the `_build/html` directory + Deploy ------ Commit the new files and the changes to `__init__.py` and push. -Create a merge request from `master` to `stable`, and merge. +Create a merge request from `develop` to `master`, and merge. Tag the merge commit with the version number: `git tag -s v0.0.0 -m "Release version 0.0.0" abc1234` Push the tag: `git push origin v0.0.0` + +Run `twine upload dist/canvasapi-0.0.0.tar.gz` to upload to PyPI. + +Compress all files in the `docs/_build/html` directory into a `.zip` file. Upload this file to PyPI to update the [documentation](https://pythonhosted.org/canvasapi/). + +Create release on GitHub for the new tag. Use the text from the changelog for content. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 7d5117bd..3672a945 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,7 +3,7 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to canvasapi's documentation! +Welcome to CanvasAPI's documentation! ====================================== Contents: From be8a5854f2b8a64c70fd0630a66eed1b6259a765 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Mon, 3 Jul 2017 14:36:58 -0400 Subject: [PATCH 02/10] Fixed a bunch of relative imports to be more explicit. Updated print function to use the one from __future__ --- canvasapi/__init__.py | 2 +- canvasapi/account.py | 12 ++++++------ canvasapi/course.py | 2 +- canvasapi/user.py | 2 +- tests/test_module.py | 2 +- tests/test_page_view.py | 2 +- tests/test_progress.py | 4 ++-- tests/test_quiz.py | 2 +- tests/test_section.py | 2 +- tests/util.py | 3 ++- 10 files changed, 17 insertions(+), 16 deletions(-) diff --git a/canvasapi/__init__.py b/canvasapi/__init__.py index 8ec3a648..78594915 100644 --- a/canvasapi/__init__.py +++ b/canvasapi/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from canvas import Canvas +from canvasapi.canvas import Canvas __all__ = ["Canvas"] diff --git a/canvasapi/account.py b/canvasapi/account.py index 30fb7bdb..a538c9a1 100644 --- a/canvasapi/account.py +++ b/canvasapi/account.py @@ -495,7 +495,7 @@ def list_groups(self, **kwargs): :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.group.Group` """ - from group import Group + from canvasapi.group import Group return PaginatedList( Group, self._requester, @@ -515,7 +515,7 @@ def create_group_category(self, name, **kwargs): :type name: str :rtype: :class:`canvasapi.group.GroupCategory` """ - from group import GroupCategory + from canvasapi.group import GroupCategory response = self._requester.request( 'POST', @@ -535,7 +535,7 @@ def list_group_categories(self): :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.group.GroupCategory` """ - from group import GroupCategory + from canvasapi.group import GroupCategory return PaginatedList( GroupCategory, @@ -605,7 +605,7 @@ def list_enrollment_terms(self, **kwargs): :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.enrollment_term.EnrollmentTerm` """ - from enrollment_term import EnrollmentTerm + from canvasapi.enrollment_term import EnrollmentTerm return PaginatedList( EnrollmentTerm, @@ -626,7 +626,7 @@ def list_user_logins(self, **kwargs): :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.login.Login` """ - from login import Login + from canvasapi.login import Login return PaginatedList( Login, @@ -649,7 +649,7 @@ def create_user_login(self, user, login, **kwargs): :type login: `dict` :rtype: :class:`canvasapi.login.Login` """ - from login import Login + from canvasapi.login import Login if isinstance(user, dict) and 'id' in user: kwargs['user'] = user diff --git a/canvasapi/course.py b/canvasapi/course.py index 15e26c45..d2e2a3bb 100644 --- a/canvasapi/course.py +++ b/canvasapi/course.py @@ -694,7 +694,7 @@ def list_groups(self, **kwargs): :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.course.Course` """ - from group import Group + from canvasapi.group import Group return PaginatedList( Group, self._requester, diff --git a/canvasapi/user.py b/canvasapi/user.py index 97aaa918..46e399f1 100644 --- a/canvasapi/user.py +++ b/canvasapi/user.py @@ -295,7 +295,7 @@ def list_groups(self, **kwargs): :rtype: :class:`canvasapi.paginated_list.PaginatedList` of :class:`canvasapi.group.Group` """ - from group import Group + from canvasapi.group import Group return PaginatedList( Group, diff --git a/tests/test_module.py b/tests/test_module.py index 9e144378..49ccbf4e 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -1,11 +1,11 @@ import unittest -import settings import requests_mock from canvasapi import Canvas from canvasapi.exceptions import RequiredFieldMissing from canvasapi.module import Module, ModuleItem +from tests import settings from tests.util import register_uris diff --git a/tests/test_page_view.py b/tests/test_page_view.py index 68ea4c09..af00c96a 100644 --- a/tests/test_page_view.py +++ b/tests/test_page_view.py @@ -4,7 +4,7 @@ from canvasapi import Canvas from tests import settings -from util import register_uris +from tests.util import register_uris @requests_mock.Mocker() diff --git a/tests/test_progress.py b/tests/test_progress.py index 80ea0156..def88d09 100644 --- a/tests/test_progress.py +++ b/tests/test_progress.py @@ -2,10 +2,10 @@ import requests_mock -import settings from canvasapi.canvas import Canvas from canvasapi.progress import Progress -from util import register_uris +from tests import settings +from tests.util import register_uris @requests_mock.Mocker() diff --git a/tests/test_quiz.py b/tests/test_quiz.py index 13c27931..5ace606d 100644 --- a/tests/test_quiz.py +++ b/tests/test_quiz.py @@ -1,10 +1,10 @@ import unittest -import settings import requests_mock from canvasapi import Canvas from canvasapi.quiz import Quiz +from tests import settings from tests.util import register_uris diff --git a/tests/test_section.py b/tests/test_section.py index e2459c84..a6101106 100644 --- a/tests/test_section.py +++ b/tests/test_section.py @@ -1,5 +1,4 @@ import unittest -import settings import requests_mock from canvasapi import Canvas @@ -7,6 +6,7 @@ from canvasapi.exceptions import RequiredFieldMissing from canvasapi.section import Section from canvasapi.submission import Submission +from tests import settings from tests.util import register_uris diff --git a/tests/util.py b/tests/util.py index 2f3cb17c..39cd2d7f 100644 --- a/tests/util.py +++ b/tests/util.py @@ -1,3 +1,4 @@ +from __future__ import print_function import json import requests_mock @@ -48,4 +49,4 @@ def register_uris(requirements, requests_mocker): headers=obj.get('headers', {}) ) except Exception as e: - print e + print(e) From d8dbe0833ba88b7fdb0c4fab12fd11381d40264f Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Wed, 5 Jul 2017 11:24:37 -0400 Subject: [PATCH 03/10] Updated for Python3 and 2.7 backwards compatibility --- canvasapi/__init__.py | 2 ++ canvasapi/account.py | 4 ++++ canvasapi/appointment_group.py | 2 ++ canvasapi/assignment.py | 2 ++ canvasapi/authentication_provider.py | 2 ++ canvasapi/avatar.py | 4 ++++ canvasapi/bookmark.py | 2 ++ canvasapi/calendar_event.py | 2 ++ canvasapi/canvas.py | 4 ++++ canvasapi/canvas_object.py | 7 +++++-- canvasapi/communication_channel.py | 2 ++ canvasapi/conversation.py | 2 ++ canvasapi/course.py | 2 ++ canvasapi/discussion_topic.py | 2 ++ canvasapi/enrollment.py | 2 ++ canvasapi/enrollment_term.py | 2 ++ canvasapi/exceptions.py | 5 +++++ canvasapi/external_feed.py | 4 ++++ canvasapi/external_tool.py | 2 ++ canvasapi/file.py | 4 ++++ canvasapi/folder.py | 4 ++++ canvasapi/group.py | 2 ++ canvasapi/login.py | 2 ++ canvasapi/module.py | 2 ++ canvasapi/notification_preference.py | 2 ++ canvasapi/page.py | 2 ++ canvasapi/page_view.py | 2 ++ canvasapi/paginated_list.py | 7 +++++-- canvasapi/progress.py | 2 ++ canvasapi/quiz.py | 2 ++ canvasapi/requester.py | 3 +++ canvasapi/section.py | 2 ++ canvasapi/submission.py | 4 ++++ canvasapi/tab.py | 2 ++ canvasapi/upload.py | 5 +++++ canvasapi/user.py | 4 ++++ canvasapi/util.py | 11 ++++++++--- setup.py | 1 + tests/settings.py | 2 ++ tests/test_account.py | 3 ++- tests/test_appointment_group.py | 3 ++- tests/test_assignment.py | 4 ++-- tests/test_authentication_providers.py | 3 ++- tests/test_bookmark.py | 3 ++- tests/test_calendar_event.py | 3 ++- tests/test_canvas.py | 4 ++-- tests/test_canvas_object.py | 1 + tests/test_communication_channel.py | 3 ++- tests/test_conversation.py | 3 ++- tests/test_course.py | 23 +++++++++++------------ tests/test_discussion_topic.py | 23 ++++++++++++----------- tests/test_enrollment.py | 3 ++- tests/test_enrollment_term.py | 3 ++- tests/test_external_feed.py | 3 ++- tests/test_external_tool.py | 5 +++-- tests/test_file.py | 3 ++- tests/test_folder.py | 3 ++- tests/test_group.py | 23 +++++++++++------------ tests/test_login.py | 3 ++- tests/test_module.py | 4 ++-- tests/test_notification_preference.py | 3 ++- tests/test_page.py | 4 ++-- tests/test_page_view.py | 3 ++- tests/test_paginated_list.py | 4 ++-- tests/test_progress.py | 3 ++- tests/test_quiz.py | 3 ++- tests/test_requester.py | 2 +- tests/test_section.py | 4 +++- tests/test_submission.py | 3 ++- tests/test_tab.py | 3 ++- tests/test_uploader.py | 7 ++++--- tests/test_user.py | 13 ++++++------- tests/test_util.py | 2 +- tests/util.py | 7 ++++--- 74 files changed, 217 insertions(+), 89 deletions(-) diff --git a/canvasapi/__init__.py b/canvasapi/__init__.py index 78594915..f5af751a 100644 --- a/canvasapi/__init__.py +++ b/canvasapi/__init__.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals + from canvasapi.canvas import Canvas __all__ = ["Canvas"] diff --git a/canvasapi/account.py b/canvasapi/account.py index a538c9a1..019a943c 100644 --- a/canvasapi/account.py +++ b/canvasapi/account.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import str + from canvasapi.canvas_object import CanvasObject from canvasapi.exceptions import RequiredFieldMissing from canvasapi.paginated_list import PaginatedList diff --git a/canvasapi/appointment_group.py b/canvasapi/appointment_group.py index 25b14303..84ef2236 100644 --- a/canvasapi/appointment_group.py +++ b/canvasapi/appointment_group.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.exceptions import RequiredFieldMissing from canvasapi.util import combine_kwargs diff --git a/canvasapi/assignment.py b/canvasapi/assignment.py index 7456098d..79152a32 100644 --- a/canvasapi/assignment.py +++ b/canvasapi/assignment.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/authentication_provider.py b/canvasapi/authentication_provider.py index 3615d895..dec3b33c 100644 --- a/canvasapi/authentication_provider.py +++ b/canvasapi/authentication_provider.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/avatar.py b/canvasapi/avatar.py index 66a830a2..315f42b8 100644 --- a/canvasapi/avatar.py +++ b/canvasapi/avatar.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import str + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/bookmark.py b/canvasapi/bookmark.py index 84b43ace..98b481fe 100644 --- a/canvasapi/bookmark.py +++ b/canvasapi/bookmark.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/calendar_event.py b/canvasapi/calendar_event.py index ba49ea97..1b811c5f 100644 --- a/canvasapi/calendar_event.py +++ b/canvasapi/calendar_event.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/canvas.py b/canvasapi/canvas.py index a4c06170..79675f86 100644 --- a/canvasapi/canvas.py +++ b/canvasapi/canvas.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import object + from canvasapi.account import Account from canvasapi.course import Course from canvasapi.exceptions import RequiredFieldMissing diff --git a/canvasapi/canvas_object.py b/canvasapi/canvas_object.py index 06a156c0..ee9d4fe2 100644 --- a/canvasapi/canvas_object.py +++ b/canvasapi/canvas_object.py @@ -1,7 +1,10 @@ +from __future__ import unicode_literals from datetime import datetime import json import re +from builtins import str, object + DATE_PATTERN = re.compile('[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z') @@ -25,7 +28,7 @@ def __init__(self, requester, attributes): def __repr__(self): # pragma: no cover classname = self.__class__.__name__ - attrs = ', '.join(['%s=%s' % (attr, val) for attr, val in self.__dict__.iteritems() if attr != 'attributes']) # noqa + attrs = ', '.join(['%s=%s' % (attr, val) for attr, val in self.__dict__.items() if attr != 'attributes']) # noqa return '%s(%s)' % (classname, attrs) def to_json(self): @@ -61,7 +64,7 @@ def set_attributes(self, attributes): """ self.attributes = attributes - for attribute, value in attributes.iteritems(): + for attribute, value in attributes.items(): self.__setattr__(attribute, value) try: diff --git a/canvasapi/communication_channel.py b/canvasapi/communication_channel.py index cd8984a7..2e4ccd5a 100644 --- a/canvasapi/communication_channel.py +++ b/canvasapi/communication_channel.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.notification_preference import NotificationPreference diff --git a/canvasapi/conversation.py b/canvasapi/conversation.py index 767f7405..52c433b3 100644 --- a/canvasapi/conversation.py +++ b/canvasapi/conversation.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/course.py b/canvasapi/course.py index d2e2a3bb..bcb61505 100644 --- a/canvasapi/course.py +++ b/canvasapi/course.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.discussion_topic import DiscussionTopic from canvasapi.exceptions import RequiredFieldMissing diff --git a/canvasapi/discussion_topic.py b/canvasapi/discussion_topic.py index 1a657a2f..19fdf5ad 100644 --- a/canvasapi/discussion_topic.py +++ b/canvasapi/discussion_topic.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.paginated_list import PaginatedList from canvasapi.util import combine_kwargs diff --git a/canvasapi/enrollment.py b/canvasapi/enrollment.py index fde3ace1..7cda3fae 100644 --- a/canvasapi/enrollment.py +++ b/canvasapi/enrollment.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/enrollment_term.py b/canvasapi/enrollment_term.py index a7fa09ec..77107448 100644 --- a/canvasapi/enrollment_term.py +++ b/canvasapi/enrollment_term.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/exceptions.py b/canvasapi/exceptions.py index 7fa60a41..3887c75a 100644 --- a/canvasapi/exceptions.py +++ b/canvasapi/exceptions.py @@ -1,3 +1,8 @@ +from __future__ import unicode_literals + +from builtins import str + + class CanvasException(Exception): # pragma: no cover """ Base class for all errors returned by the Canvas API. diff --git a/canvasapi/external_feed.py b/canvasapi/external_feed.py index 8769ba01..e2307d7d 100644 --- a/canvasapi/external_feed.py +++ b/canvasapi/external_feed.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import str + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/external_tool.py b/canvasapi/external_tool.py index e1e2700c..4c61bc14 100644 --- a/canvasapi/external_tool.py +++ b/canvasapi/external_tool.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.exceptions import CanvasException from canvasapi.util import combine_kwargs diff --git a/canvasapi/file.py b/canvasapi/file.py index 6b82c089..0a9d7cca 100644 --- a/canvasapi/file.py +++ b/canvasapi/file.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import str + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/folder.py b/canvasapi/folder.py index a66adfba..0baea1f3 100644 --- a/canvasapi/folder.py +++ b/canvasapi/folder.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import str + from canvasapi.canvas_object import CanvasObject from canvasapi.paginated_list import PaginatedList from canvasapi.util import combine_kwargs diff --git a/canvasapi/group.py b/canvasapi/group.py index 22efa73d..84c44ddb 100644 --- a/canvasapi/group.py +++ b/canvasapi/group.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.discussion_topic import DiscussionTopic from canvasapi.folder import Folder diff --git a/canvasapi/login.py b/canvasapi/login.py index 25cc22f8..955b4c50 100644 --- a/canvasapi/login.py +++ b/canvasapi/login.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/module.py b/canvasapi/module.py index b1be178e..60a289ca 100644 --- a/canvasapi/module.py +++ b/canvasapi/module.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.exceptions import RequiredFieldMissing from canvasapi.paginated_list import PaginatedList diff --git a/canvasapi/notification_preference.py b/canvasapi/notification_preference.py index 22c58f14..5983e7f6 100644 --- a/canvasapi/notification_preference.py +++ b/canvasapi/notification_preference.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/page.py b/canvasapi/page.py index 594b78a5..fd6c26f3 100644 --- a/canvasapi/page.py +++ b/canvasapi/page.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs from canvasapi.paginated_list import PaginatedList diff --git a/canvasapi/page_view.py b/canvasapi/page_view.py index 216b02a5..f5848135 100644 --- a/canvasapi/page_view.py +++ b/canvasapi/page_view.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/paginated_list.py b/canvasapi/paginated_list.py index 0e27fbcc..fec05e15 100644 --- a/canvasapi/paginated_list.py +++ b/canvasapi/paginated_list.py @@ -1,5 +1,8 @@ +from __future__ import unicode_literals import re +from builtins import object + class PaginatedList(object): """ @@ -25,7 +28,7 @@ def __init__( def __getitem__(self, index): assert isinstance(index, (int, slice)) - if isinstance(index, (int, long)): + if isinstance(index, int): self.__get_up_to_index(index) return self.__elements[index] else: @@ -81,7 +84,7 @@ def _get_next_page(self): return content - class _Slice: + class _Slice(object): def __init__(self, the_list, the_slice): self.__list = the_list self.__start = the_slice.start or 0 diff --git a/canvasapi/progress.py b/canvasapi/progress.py index edacadfa..962951aa 100644 --- a/canvasapi/progress.py +++ b/canvasapi/progress.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/quiz.py b/canvasapi/quiz.py index eef668bb..04f87449 100644 --- a/canvasapi/quiz.py +++ b/canvasapi/quiz.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.util import combine_kwargs diff --git a/canvasapi/requester.py b/canvasapi/requester.py index e12666ca..48ea06ce 100644 --- a/canvasapi/requester.py +++ b/canvasapi/requester.py @@ -1,3 +1,6 @@ +from __future__ import unicode_literals + +from builtins import object import requests from canvasapi.exceptions import ( diff --git a/canvasapi/section.py b/canvasapi/section.py index 60609d0b..19dd63b7 100644 --- a/canvasapi/section.py +++ b/canvasapi/section.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject from canvasapi.exceptions import RequiredFieldMissing from canvasapi.paginated_list import PaginatedList diff --git a/canvasapi/submission.py b/canvasapi/submission.py index 27473c17..391c38be 100644 --- a/canvasapi/submission.py +++ b/canvasapi/submission.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import str + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/tab.py b/canvasapi/tab.py index c35eaf5d..9c22ac40 100644 --- a/canvasapi/tab.py +++ b/canvasapi/tab.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/upload.py b/canvasapi/upload.py index 793136a1..7394c2ec 100644 --- a/canvasapi/upload.py +++ b/canvasapi/upload.py @@ -1,5 +1,8 @@ +from __future__ import unicode_literals import os +from builtins import object + from canvasapi.util import combine_kwargs @@ -54,9 +57,11 @@ def upload(self, response): """ response = response.json() if not response.get('upload_url'): + self.file.close() raise ValueError('Bad API response. No upload_url.') if not response.get('upload_params'): + self.file.close() raise ValueError('Bad API response. No upload_params.') kwargs = response.get('upload_params') diff --git a/canvasapi/user.py b/canvasapi/user.py index 46e399f1..232bbde2 100644 --- a/canvasapi/user.py +++ b/canvasapi/user.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals + +from builtins import str + from canvasapi.bookmark import Bookmark from canvasapi.calendar_event import CalendarEvent from canvasapi.canvas_object import CanvasObject diff --git a/canvasapi/util.py b/canvasapi/util.py index b1e2cd3a..f9467c9e 100644 --- a/canvasapi/util.py +++ b/canvasapi/util.py @@ -1,3 +1,8 @@ +from __future__ import unicode_literals + +from builtins import str + + def combine_kwargs(**kwargs): """ Combines a list of keyword arguments into a single dictionary. @@ -8,7 +13,7 @@ def flatten_dict(prefix, key, value): new_prefix = prefix + '[' + str(key) + ']' if isinstance(value, dict): d = {} - for k, v in value.iteritems(): + for k, v in value.items(): d.update(flatten_dict(new_prefix, k, v)) return d else: @@ -17,10 +22,10 @@ def flatten_dict(prefix, key, value): combined_kwargs = {} # Loop through all kwargs. - for kw, arg in kwargs.iteritems(): + for kw, arg in kwargs.items(): if isinstance(arg, dict): # If the argument is a dictionary, flatten it. - for key, value in arg.iteritems(): + for key, value in arg.items(): combined_kwargs.update(flatten_dict(str(kw), key, value)) else: combined_kwargs.update({str(kw): arg}) diff --git a/setup.py b/setup.py index dcc996ca..2f9871ab 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import re from setuptools import setup diff --git a/tests/settings.py b/tests/settings.py index 636763d8..71d0b142 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + BASE_URL = 'http://example.com/api/v1/' API_KEY = '123' diff --git a/tests/test_account.py b/tests/test_account.py index c296f4ea..58796bbe 100644 --- a/tests/test_account.py +++ b/tests/test_account.py @@ -1,6 +1,8 @@ +from __future__ import unicode_literals import datetime import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -21,7 +23,6 @@ @requests_mock.Mocker() class TestAccount(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_appointment_group.py b/tests/test_appointment_group.py index e8935c1f..81bf5c82 100644 --- a/tests/test_appointment_group.py +++ b/tests/test_appointment_group.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -12,7 +14,6 @@ @requests_mock.Mocker() class TestAppointmentGroup(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_assignment.py b/tests/test_assignment.py index 915d0275..f1158d65 100644 --- a/tests/test_assignment.py +++ b/tests/test_assignment.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestAssignment(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -49,7 +50,6 @@ def test__str__(self, m): @requests_mock.Mocker() class TestAssignmentGroup(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_authentication_providers.py b/tests/test_authentication_providers.py index 6e60a4a8..368f313a 100644 --- a/tests/test_authentication_providers.py +++ b/tests/test_authentication_providers.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestAuthenticationProvider(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_bookmark.py b/tests/test_bookmark.py index db54218b..e923dfa2 100644 --- a/tests/test_bookmark.py +++ b/tests/test_bookmark.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestBookmark(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_calendar_event.py b/tests/test_calendar_event.py index 9b8d0dbd..0d10c38c 100644 --- a/tests/test_calendar_event.py +++ b/tests/test_calendar_event.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestCalendarEvent(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_canvas.py b/tests/test_canvas.py index 0be45707..8ceae567 100644 --- a/tests/test_canvas.py +++ b/tests/test_canvas.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import unittest from datetime import datetime @@ -22,7 +23,6 @@ @requests_mock.Mocker() class TestCanvas(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -86,7 +86,7 @@ def test_get_course_with_start_date(self, m): course = self.canvas.get_course(2) self.assertTrue(hasattr(course, 'start_at')) - self.assertIsInstance(course.start_at, (str, unicode)) + self.assertIsInstance(course.start_at, str) self.assertTrue(hasattr(course, 'start_at_date')) self.assertIsInstance(course.start_at_date, datetime) diff --git a/tests/test_canvas_object.py b/tests/test_canvas_object.py index e86f566d..8bb48754 100644 --- a/tests/test_canvas_object.py +++ b/tests/test_canvas_object.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import unittest from canvasapi.canvas_object import CanvasObject diff --git a/tests/test_communication_channel.py b/tests/test_communication_channel.py index ca28283f..20f54259 100644 --- a/tests/test_communication_channel.py +++ b/tests/test_communication_channel.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestCommunicationChannel(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_conversation.py b/tests/test_conversation.py index 216c0847..a579e305 100644 --- a/tests/test_conversation.py +++ b/tests/test_conversation.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestConversation(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_course.py b/tests/test_course.py index cb9f46b4..c37815a8 100644 --- a/tests/test_course.py +++ b/tests/test_course.py @@ -1,7 +1,9 @@ +from __future__ import unicode_literals import unittest import uuid import os +from builtins import str import requests_mock from canvasapi import Canvas @@ -29,7 +31,6 @@ @requests_mock.Mocker() class TestCourse(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -135,7 +136,7 @@ def test_preview_html(self, m): html_str = "

hello

" prev_html = self.course.preview_html(html_str) - self.assertIsInstance(prev_html, (str, unicode)) + self.assertIsInstance(prev_html, str) self.assertEqual(prev_html, "

hello

") # get_settings() @@ -159,10 +160,9 @@ def test_update_settings(self, m): def test_upload(self, m): register_uris({'course': ['upload', 'upload_final']}, m) - filename = 'testfile_%s' % uuid.uuid4().hex - file = open(filename, 'w+') - - response = self.course.upload(file) + filename = 'testfile_course_%s' % uuid.uuid4().hex + with open(filename, 'w+') as file: + response = self.course.upload(file) self.assertTrue(response[0]) self.assertIsInstance(response[1], dict) @@ -450,7 +450,7 @@ def test_get_discussion_topic(self, m): discussion = self.course.get_discussion_topic(topic_id) self.assertIsInstance(discussion, DiscussionTopic) self.assertTrue(hasattr(discussion, 'course_id')) - self.assertEquals(discussion.course_id, 1) + self.assertEqual(discussion.course_id, 1) # get_full_discussion_topic() def test_get_full_discussion_topic(self, m): @@ -461,7 +461,7 @@ def test_get_full_discussion_topic(self, m): self.assertIsInstance(discussion, DiscussionTopic) self.assertTrue(hasattr(discussion, 'view')) self.assertTrue(hasattr(discussion, 'participants')) - self.assertEquals(discussion.course_id, 1) + self.assertEqual(discussion.course_id, 1) # get_discussion_topics() def test_get_discussion_topics(self, m): @@ -471,7 +471,7 @@ def test_get_discussion_topics(self, m): discussion_list = [discussion for discussion in response] self.assertIsInstance(discussion_list[0], DiscussionTopic) self.assertTrue(hasattr(discussion_list[0], 'course_id')) - self.assertEquals(2, len(discussion_list)) + self.assertEqual(2, len(discussion_list)) # create_discussion_topic() def test_create_discussion_topic(self, m): @@ -481,8 +481,8 @@ def test_create_discussion_topic(self, m): discussion = self.course.create_discussion_topic() self.assertIsInstance(discussion, DiscussionTopic) self.assertTrue(hasattr(discussion, 'course_id')) - self.assertEquals(title, discussion.title) - self.assertEquals(discussion.course_id, 1) + self.assertEqual(title, discussion.title) + self.assertEqual(discussion.course_id, 1) # reorder_pinned_topics() def test_reorder_pinned_topics(self, m): @@ -782,7 +782,6 @@ def test_update_tab(self, m): @requests_mock.Mocker() class TestCourseNickname(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_discussion_topic.py b/tests/test_discussion_topic.py index e07b5daa..103831c3 100644 --- a/tests/test_discussion_topic.py +++ b/tests/test_discussion_topic.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -13,7 +15,6 @@ @requests_mock.Mocker() class TestDiscussionTopic(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -49,7 +50,7 @@ def test_update(self, m): discussion = self.discussion_topic.update() self.assertIsInstance(discussion, DiscussionTopic) self.assertTrue(hasattr(discussion, 'course_id')) - self.assertEquals(discussion.course_id, 1) + self.assertEqual(discussion.course_id, 1) # update_entry() def test_update_entry(self, m): @@ -81,8 +82,8 @@ def test_list_topic_entries(self, m): entries = self.discussion_topic.list_topic_entries() entry_list = [entry for entry in entries] self.assertIsInstance(entry_list[0], DiscussionTopic) - self.assertEquals(entry_list[0].id, 1) - self.assertEquals(entry_list[0].user_id, 1) + self.assertEqual(entry_list[0].id, 1) + self.assertEqual(entry_list[0].user_id, 1) # post_reply() def test_post_reply(self, m): @@ -91,7 +92,7 @@ def test_post_reply(self, m): message = "Message 1" reply = self.discussion_topic.post_reply(1) self.assertIsInstance(reply, DiscussionTopic) - self.assertEquals(reply.message, message) + self.assertEqual(reply.message, message) self.assertTrue(hasattr(reply, 'created_at')) self.assertTrue(hasattr(reply, 'message')) @@ -102,7 +103,7 @@ def test_list_entry_replies(self, m): replies = self.discussion_topic.list_entry_replies(1) reply_list = [reply for reply in replies] self.assertIsInstance(reply_list[0], DiscussionTopic) - self.assertEquals(reply_list[0].id, 1) + self.assertEqual(reply_list[0].id, 1) # list_entries() def test_list_entries(self, m): @@ -111,7 +112,7 @@ def test_list_entries(self, m): entries = self.discussion_topic.list_entries() entry_list = [entry for entry in entries] self.assertIsInstance(entry_list[0], DiscussionTopic) - self.assertEquals(entry_list[0].id, 1) + self.assertEqual(entry_list[0].id, 1) # mark_as_read() def test_mark_as_read(self, m): @@ -231,10 +232,10 @@ def test_unsubscribe_status(self, m): # parent_id def test_parent_id_course(self, m): - self.assertEquals(self.discussion_topic.parent_id, 1) + self.assertEqual(self.discussion_topic.parent_id, 1) def test_parent_id_group(self, m): - self.assertEquals(self.discussion_topic_group.parent_id, 1) + self.assertEqual(self.discussion_topic_group.parent_id, 1) def test_parent_id_no_id(self, m): discussion = DiscussionTopic(self.canvas._Canvas__requester, {'id': 1}) @@ -243,10 +244,10 @@ def test_parent_id_no_id(self, m): # parent_type def test_parent_type_course(self, m): - self.assertEquals(self.discussion_topic.parent_type, 'course') + self.assertEqual(self.discussion_topic.parent_type, 'course') def test_parent_type_group(self, m): - self.assertEquals(self.discussion_topic_group.parent_type, 'group') + self.assertEqual(self.discussion_topic_group.parent_type, 'group') def test_parent_type_no_id(self, m): discussion = DiscussionTopic(self.canvas._Canvas__requester, {'id': 1}) diff --git a/tests/test_enrollment.py b/tests/test_enrollment.py index c9f943ea..3fb5f2b1 100644 --- a/tests/test_enrollment.py +++ b/tests/test_enrollment.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi.canvas import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestEnrollment(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_enrollment_term.py b/tests/test_enrollment_term.py index 88ce42b1..1043fe19 100644 --- a/tests/test_enrollment_term.py +++ b/tests/test_enrollment_term.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestEnrollmentTerm(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_external_feed.py b/tests/test_external_feed.py index e75cfa50..bd68fda1 100644 --- a/tests/test_external_feed.py +++ b/tests/test_external_feed.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -10,7 +12,6 @@ @requests_mock.Mocker() class TestExternalFeed(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_external_tool.py b/tests/test_external_tool.py index 534c4691..439286ea 100644 --- a/tests/test_external_tool.py +++ b/tests/test_external_tool.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -14,7 +16,6 @@ @requests_mock.Mocker() class TestExternalTool(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -93,7 +94,7 @@ def test_get_sessionless_launch_url(self, m): requires = {'external_tool': ['get_sessionless_launch_url_course']} register_uris(requires, m) - self.assertIsInstance(self.ext_tool_course.get_sessionless_launch_url(), (str, unicode)) + self.assertIsInstance(self.ext_tool_course.get_sessionless_launch_url(), str) def test_get_sessionless_launch_url_no_url(self, m): requires = { diff --git a/tests/test_file.py b/tests/test_file.py index f9b406fc..f91c6f75 100644 --- a/tests/test_file.py +++ b/tests/test_file.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestFile(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_folder.py b/tests/test_folder.py index 6eabd965..9bdc2e00 100644 --- a/tests/test_folder.py +++ b/tests/test_folder.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -12,7 +14,6 @@ @requests_mock.Mocker() class TestFolder(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_group.py b/tests/test_group.py index 265bc3ce..eacebce1 100644 --- a/tests/test_group.py +++ b/tests/test_group.py @@ -1,7 +1,9 @@ +from __future__ import unicode_literals import os import unittest import uuid +from builtins import str import requests_mock from canvasapi import Canvas @@ -20,7 +22,6 @@ @requests_mock.Mocker() class TestGroup(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -139,9 +140,9 @@ def test_remove_user(self, m): def test_upload(self, m): register_uris({'group': ['upload', 'upload_final']}, m) - filename = 'testfile_%s' % uuid.uuid4().hex - file = open(filename, 'w+') - response = self.group.upload(file) + filename = 'testfile_group_%s' % uuid.uuid4().hex + with open(filename, 'w+') as file: + response = self.group.upload(file) self.assertTrue(response[0]) self.assertIsInstance(response[1], dict) self.assertIn('url', response[1]) @@ -207,8 +208,8 @@ def test_get_discussion_topic(self, m): discussion = self.group.get_discussion_topic(group_id) self.assertIsInstance(discussion, DiscussionTopic) self.assertTrue(hasattr(discussion, 'group_id')) - self.assertEquals(group_id, discussion.id) - self.assertEquals(discussion.group_id, 1) + self.assertEqual(group_id, discussion.id) + self.assertEqual(discussion.group_id, 1) # get_full_discussion_topic def test_get_full_discussion_topic(self, m): @@ -219,7 +220,7 @@ def test_get_full_discussion_topic(self, m): self.assertIsInstance(discussion, DiscussionTopic) self.assertTrue(hasattr(discussion, 'view')) self.assertTrue(hasattr(discussion, 'participants')) - self.assertEquals(discussion.group_id, 1) + self.assertEqual(discussion.group_id, 1) # get_discussion_topics() def test_get_discussion_topics(self, m): @@ -229,7 +230,7 @@ def test_get_discussion_topics(self, m): discussion_list = [discussion for discussion in response] self.assertIsInstance(discussion_list[0], DiscussionTopic) self.assertTrue(hasattr(discussion_list[0], 'group_id')) - self.assertEquals(2, len(discussion_list)) + self.assertEqual(2, len(discussion_list)) # create_discussion_topic() def test_create_discussion_topic(self, m): @@ -239,8 +240,8 @@ def test_create_discussion_topic(self, m): discussion = self.group.create_discussion_topic() self.assertTrue(hasattr(discussion, 'group_id')) self.assertIsInstance(discussion, DiscussionTopic) - self.assertEquals(discussion.title, title) - self.assertEquals(discussion.group_id, 1) + self.assertEqual(discussion.title, title) + self.assertEqual(discussion.group_id, 1) # reorder_pinned_topics() def test_reorder_pinned_topics(self, m): @@ -335,7 +336,6 @@ def test_list_tabs(self, m): @requests_mock.Mocker() class TestGroupMembership(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -379,7 +379,6 @@ def test_remove_self(self, m): @requests_mock.Mocker() class TestGroupCategory(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) with requests_mock.Mocker() as m: diff --git a/tests/test_login.py b/tests/test_login.py index 5e012234..98b09e63 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestLogin(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_module.py b/tests/test_module.py index 49ccbf4e..fbe246bf 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -12,7 +14,6 @@ @requests_mock.Mocker() class TestModule(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -112,7 +113,6 @@ def test__str__(self, m): @requests_mock.Mocker() class TestModuleItem(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_notification_preference.py b/tests/test_notification_preference.py index 1a2fdcbb..92de0692 100644 --- a/tests/test_notification_preference.py +++ b/tests/test_notification_preference.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -10,7 +12,6 @@ @requests_mock.Mocker() class TestNotificationPreference(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_page.py b/tests/test_page.py index c10bff75..a979c641 100644 --- a/tests/test_page.py +++ b/tests/test_page.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi.canvas import Canvas @@ -13,7 +15,6 @@ @requests_mock.Mocker() class TestPage(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -136,7 +137,6 @@ def test_get_parent_group(self, m): @requests_mock.Mocker() class TestPageRevision(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_page_view.py b/tests/test_page_view.py index af00c96a..f3605e10 100644 --- a/tests/test_page_view.py +++ b/tests/test_page_view.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -10,7 +12,6 @@ @requests_mock.Mocker() class TestPageView(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_paginated_list.py b/tests/test_paginated_list.py index 889424d5..25c4124c 100644 --- a/tests/test_paginated_list.py +++ b/tests/test_paginated_list.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import unittest import requests_mock @@ -12,7 +13,6 @@ @requests_mock.Mocker() class TestPaginatedList(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) self.requester = self.canvas._Canvas__requester @@ -100,7 +100,7 @@ def test_iterator(self, m): ) list_1 = [item for item in pag_list] list_2 = [item for item in pag_list] - self.assertEqual(cmp(list_1, list_2), 0) + self.assertEqual(list_1, list_2) # get item def test_getitem_first(self, m): diff --git a/tests/test_progress.py b/tests/test_progress.py index def88d09..862f9ef2 100644 --- a/tests/test_progress.py +++ b/tests/test_progress.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi.canvas import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestProgress(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_quiz.py b/tests/test_quiz.py index 5ace606d..83d133ff 100644 --- a/tests/test_quiz.py +++ b/tests/test_quiz.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -11,7 +13,6 @@ @requests_mock.Mocker() class TestQuiz(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_requester.py b/tests/test_requester.py index 57577c61..1193c337 100644 --- a/tests/test_requester.py +++ b/tests/test_requester.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import unittest import requests_mock @@ -14,7 +15,6 @@ @requests_mock.Mocker() class TestRequester(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) self.requester = self.canvas._Canvas__requester diff --git a/tests/test_section.py b/tests/test_section.py index a6101106..1378b9b7 100644 --- a/tests/test_section.py +++ b/tests/test_section.py @@ -1,4 +1,7 @@ +from __future__ import unicode_literals import unittest + +from builtins import str import requests_mock from canvasapi import Canvas @@ -13,7 +16,6 @@ @requests_mock.Mocker() class TestSection(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_submission.py b/tests/test_submission.py index 2c5bd5a2..bcd546d4 100644 --- a/tests/test_submission.py +++ b/tests/test_submission.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -10,7 +12,6 @@ @requests_mock.Mocker() class TestSubmission(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_tab.py b/tests/test_tab.py index 95683c6a..80277166 100644 --- a/tests/test_tab.py +++ b/tests/test_tab.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import unittest +from builtins import str import requests_mock from canvasapi import Canvas @@ -10,7 +12,6 @@ @requests_mock.Mocker() class TestTab(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_uploader.py b/tests/test_uploader.py index 368f1e62..e0da56fc 100644 --- a/tests/test_uploader.py +++ b/tests/test_uploader.py @@ -1,6 +1,7 @@ +from __future__ import unicode_literals +import os import unittest import uuid -import os import requests_mock @@ -13,15 +14,15 @@ @requests_mock.Mocker() class TestUploader(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) self.requester = self.canvas._Canvas__requester - self.filename = 'testfile_%s' % uuid.uuid4().hex + self.filename = 'testfile_uploader_%s' % uuid.uuid4().hex self.file = open(self.filename, 'w+') def tearDown(self): + self.file.close() # http://stackoverflow.com/a/10840586 # Not as stupid as it looks. try: diff --git a/tests/test_user.py b/tests/test_user.py index 68249b56..6241f983 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -1,7 +1,9 @@ +from __future__ import unicode_literals +import os import unittest import uuid -import os +from builtins import str import requests_mock from canvasapi import Canvas @@ -25,7 +27,6 @@ @requests_mock.Mocker() class TestUser(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) @@ -194,10 +195,9 @@ def test_list_enrollments(self, m): def test_upload(self, m): register_uris({'user': ['upload', 'upload_final']}, m) - filename = 'testfile_%s' % uuid.uuid4().hex - file = open(filename, 'w+') - - response = self.user.upload(file) + filename = 'testfile_user_%s' % uuid.uuid4().hex + with open(filename, 'w+') as file: + response = self.user.upload(file) self.assertTrue(response[0]) self.assertIsInstance(response[1], dict) @@ -360,7 +360,6 @@ def test_remove_observee(self, m): @requests_mock.Mocker() class TestUserDisplay(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/test_util.py b/tests/test_util.py index e84ea439..f61b3ef5 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import unittest import requests_mock @@ -13,7 +14,6 @@ @requests_mock.Mocker() class TestUtil(unittest.TestCase): - @classmethod def setUp(self): self.canvas = Canvas(settings.BASE_URL, settings.API_KEY) diff --git a/tests/util.py b/tests/util.py index 39cd2d7f..5dcb1f8a 100644 --- a/tests/util.py +++ b/tests/util.py @@ -1,4 +1,4 @@ -from __future__ import print_function +from __future__ import print_function, unicode_literals import json import requests_mock @@ -15,10 +15,11 @@ def register_uris(requirements, requests_mocker): :param requirements: dict :param requests_mocker: requests_mock.mocker.Mocker """ - for fixture, objects in requirements.iteritems(): + for fixture, objects in requirements.items(): try: - data = json.loads(open('tests/fixtures/{}.json'.format(fixture)).read()) + with open('tests/fixtures/{}.json'.format(fixture)) as file: + data = json.loads(file.read()) except IOError: raise ValueError('Fixture {}.json contains invalid JSON.'.format(fixture)) From 7d31df069f14e53b6ebd6e799b8fa54aab67ede1 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Wed, 5 Jul 2017 12:47:18 -0400 Subject: [PATCH 04/10] added python 3 versions to .travis.yml. Added imports of python3's str for 2.7 compat --- .travis.yml | 4 ++++ canvasapi/upload.py | 2 +- tests/test_canvas.py | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 83a80fd5..324a68a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ language: python python: - 2.7 + - 3.3 + - 3.4 + - 3.5 + - 3.6 install: - pip install -r tests_requirements.txt - pip install coveralls diff --git a/canvasapi/upload.py b/canvasapi/upload.py index 7394c2ec..ddcd2833 100644 --- a/canvasapi/upload.py +++ b/canvasapi/upload.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals import os -from builtins import object +from builtins import object, str from canvasapi.util import combine_kwargs diff --git a/tests/test_canvas.py b/tests/test_canvas.py index 8ceae567..a87dd857 100644 --- a/tests/test_canvas.py +++ b/tests/test_canvas.py @@ -2,6 +2,7 @@ import unittest from datetime import datetime +from builtins import str import requests_mock from canvasapi import Canvas From 8aa06bf4b435e9111734f175160f1a8cc1f3bd3b Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Wed, 5 Jul 2017 12:53:42 -0400 Subject: [PATCH 05/10] added future package to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 78a61867..1536591e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ +future==0.16.0 requests==2.10.0 six==1.10.0 From 9043ef98ea402e1e9d7f0c230278eba59e7d7226 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Wed, 5 Jul 2017 13:13:31 -0400 Subject: [PATCH 06/10] Removed catch for unicode encoding exception since it shouldn't be triggered anymore. Updated setup.py --- canvasapi/canvas_object.py | 12 ++++-------- setup.py | 7 ++++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/canvasapi/canvas_object.py b/canvasapi/canvas_object.py index ee9d4fe2..46b56d9a 100644 --- a/canvasapi/canvas_object.py +++ b/canvasapi/canvas_object.py @@ -67,11 +67,7 @@ def set_attributes(self, attributes): for attribute, value in attributes.items(): self.__setattr__(attribute, value) - try: - # datetime field - if DATE_PATTERN.match(str(value)): - date = datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ') - self.__setattr__(attribute + '_date', date) - # Non-unicode character. We can skip over this attribute. - except UnicodeEncodeError: - continue + # datetime field + if DATE_PATTERN.match(str(value)): + date = datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ') + self.__setattr__(attribute + '_date', date) diff --git a/setup.py b/setup.py index 2f9871ab..69629b91 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ license='MIT License', packages=['canvasapi'], include_package_data=True, - install_requires=['requests'], + install_requires=['requests', 'future'], zip_safe=False, classifiers=[ 'Development Status :: 3 - Alpha', @@ -33,6 +33,11 @@ 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Software Development :: Libraries', ], ) From e3eeda0bd7ce422963f598f9cb67855a3af0c762 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Thu, 6 Jul 2017 11:08:08 -0400 Subject: [PATCH 07/10] Reworked file handling when passing a path to Uploader. Now correctly opens and closes file appropriately. --- canvasapi/upload.py | 28 +++++++++++++++++++++------- tests/test_uploader.py | 1 + 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/canvasapi/upload.py b/canvasapi/upload.py index ddcd2833..1489df94 100644 --- a/canvasapi/upload.py +++ b/canvasapi/upload.py @@ -23,8 +23,9 @@ def __init__(self, requester, url, file, **kwargs): if isinstance(file, str): if not os.path.exists(file): raise IOError('File ' + file + ' does not exist.') - - file = open(file, 'rb') + self._using_filename = True + else: + self._using_filename = False self._requester = requester self.url = url @@ -35,14 +36,22 @@ def start(self): """ Request an upload token. """ - self.kwargs['name'] = os.path.basename(self.file.name) - self.kwargs['size'] = os.fstat(self.file.fileno()).st_size + # open file if using filename + file = open(self.file, 'rb') if self._using_filename else self.file + + self.kwargs['name'] = os.path.basename(file.name) + self.kwargs['size'] = os.fstat(file.fileno()).st_size response = self._requester.request( 'POST', self.url, **combine_kwargs(**self.kwargs) ) + + # close file if using filename + if self._using_filename: + file.close() + return self.upload(response) def upload(self, response): @@ -57,15 +66,16 @@ def upload(self, response): """ response = response.json() if not response.get('upload_url'): - self.file.close() raise ValueError('Bad API response. No upload_url.') if not response.get('upload_params'): - self.file.close() raise ValueError('Bad API response. No upload_params.') + # open file if using filename + file = open(self.file, 'rb') if self._using_filename else self.file + kwargs = response.get('upload_params') - kwargs['file'] = self.file + kwargs['file'] = file response_json = self._requester.request( 'POST', @@ -74,6 +84,10 @@ def upload(self, response): **kwargs ).json() + # close file if using filename + if self._using_filename: + file.close() + if 'url' in response_json: return (True, response_json) diff --git a/tests/test_uploader.py b/tests/test_uploader.py index e0da56fc..a6d992ce 100644 --- a/tests/test_uploader.py +++ b/tests/test_uploader.py @@ -23,6 +23,7 @@ def setUp(self): def tearDown(self): self.file.close() + # http://stackoverflow.com/a/10840586 # Not as stupid as it looks. try: From 9e00f957a83f3dc409b3b423579585f6c753967b Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Thu, 6 Jul 2017 16:03:21 -0400 Subject: [PATCH 08/10] Reworked how Uploader handles opening files from a path. Moved code for requesting an upload token to its own method. start method now handles opening/closing files as necessary --- canvasapi/upload.py | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/canvasapi/upload.py b/canvasapi/upload.py index 1489df94..f9b0ae6b 100644 --- a/canvasapi/upload.py +++ b/canvasapi/upload.py @@ -17,7 +17,7 @@ def __init__(self, requester, url, file, **kwargs): :type requester: :class:`canvasapi.requester.Requester` :param url: The URL to upload the file to. :type url: str - :param file: The file or path of the file to upload. + :param file: A file handler or path of the file to upload. :type file: file or str """ if isinstance(file, str): @@ -34,11 +34,29 @@ def __init__(self, requester, url, file, **kwargs): def start(self): """ - Request an upload token. + Kick off uploading process. Handles open/closing file if a path + is passed. + + :calls: request_upload_token + :returns: True if the file uploaded successfully, False \ + otherwise, and the JSON response from the API. + :rtype: tuple + """ + if self._using_filename: + with open(self.file, 'rb') as file: + return self.request_upload_token(file) + else: + return self.request_upload_token(self.file) + + def request_upload_token(self, file): """ - # open file if using filename - file = open(self.file, 'rb') if self._using_filename else self.file + Request an upload token. + :param file: A file handler pointing to the file to upload. + :returns: True if the file uploaded successfully, False otherwise, \ + and the JSON response from the API. + :rtype: tuple + """ self.kwargs['name'] = os.path.basename(file.name) self.kwargs['size'] = os.fstat(file.fileno()).st_size @@ -48,20 +66,17 @@ def start(self): **combine_kwargs(**self.kwargs) ) - # close file if using filename - if self._using_filename: - file.close() - - return self.upload(response) + return self.upload(response, file) - def upload(self, response): + def upload(self, response, file): """ Upload the file. :param response: The response from the upload request. :type response: dict + :param file: A file handler pointing to the file to upload. :returns: True if the file uploaded successfully, False otherwise, \ - and the JSON response from the API. + and the JSON response from the API. :rtype: tuple """ response = response.json() @@ -71,9 +86,6 @@ def upload(self, response): if not response.get('upload_params'): raise ValueError('Bad API response. No upload_params.') - # open file if using filename - file = open(self.file, 'rb') if self._using_filename else self.file - kwargs = response.get('upload_params') kwargs['file'] = file @@ -84,10 +96,6 @@ def upload(self, response): **kwargs ).json() - # close file if using filename - if self._using_filename: - file.close() - if 'url' in response_json: return (True, response_json) From 9c2d100a43fc0ac7a90d934ea936b6cfdabaa930 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Mon, 10 Jul 2017 11:00:32 -0400 Subject: [PATCH 09/10] Added support for get_file to Canvas, Course, Group and User objects. --- canvasapi/canvas.py | 21 +++++- canvasapi/course.py | 19 ++++++ canvasapi/group.py | 19 ++++++ canvasapi/user.py | 19 ++++++ tests/fixtures/course.json | 132 ++++++++++++++++++++----------------- tests/fixtures/file.json | 10 +++ tests/fixtures/group.json | 10 +++ tests/fixtures/user.json | 10 +++ tests/test_canvas.py | 10 +++ tests/test_course.py | 9 +++ tests/test_group.py | 9 +++ tests/test_user.py | 9 +++ 12 files changed, 215 insertions(+), 62 deletions(-) diff --git a/canvasapi/canvas.py b/canvasapi/canvas.py index 79675f86..c7d2778f 100644 --- a/canvasapi/canvas.py +++ b/canvasapi/canvas.py @@ -5,6 +5,7 @@ from canvasapi.account import Account from canvasapi.course import Course from canvasapi.exceptions import RequiredFieldMissing +from canvasapi.file import File from canvasapi.folder import Folder from canvasapi.group import Group, GroupCategory from canvasapi.paginated_list import PaginatedList @@ -761,9 +762,27 @@ def list_group_participants(self, appointment_group_id, **kwargs): **combine_kwargs(**kwargs) ) + def get_file(self, file_id, **kwargs): + """ + Return the standard attachment json object for a file. + + :calls: `GET /api/v1/files/:id \ + `_ + + :param file_id: The ID of the file to retrieve. + :type file_id: int + :rtype: :class:`canvasapi.file.File` + """ + response = self.__requester.request( + 'GET', + 'files/{}'.format(file_id), + **combine_kwargs(**kwargs) + ) + return File(self.__requester, response.json()) + def get_folder(self, folder_id): """ - Returns the details for a folder + Return the details for a folder :calls: `GET /api/v1/folders/:id \ `_ diff --git a/canvasapi/course.py b/canvasapi/course.py index bcb61505..296c8d79 100644 --- a/canvasapi/course.py +++ b/canvasapi/course.py @@ -767,6 +767,25 @@ def get_discussion_topic(self, topic_id): return DiscussionTopic(self._requester, response_json) + def get_file(self, file_id, **kwargs): + """ + Return the standard attachment json object for a file. + + :calls: `GET /api/v1/courses/:course_id/files/:id \ + `_ + + :param file_id: The ID of the file to retrieve. + :type file_id: int + :rtype: :class:`canvasapi.file.File` + """ + from canvasapi.file import File + response = self._requester.request( + 'GET', + 'courses/{}/files/{}'.format(self.id, file_id), + **combine_kwargs(**kwargs) + ) + return File(self._requester, response.json()) + def get_full_discussion_topic(self, topic_id): """ Return a cached structure of the discussion topic. diff --git a/canvasapi/group.py b/canvasapi/group.py index 84c44ddb..1d62f839 100644 --- a/canvasapi/group.py +++ b/canvasapi/group.py @@ -379,6 +379,25 @@ def get_discussion_topic(self, topic_id): return DiscussionTopic(self._requester, response_json) + def get_file(self, file_id, **kwargs): + """ + Return the standard attachment json object for a file. + + :calls: `GET /api/v1/groups/:group_id/files/:id \ + `_ + + :param file_id: The ID of the file to retrieve. + :type file_id: int + :rtype: :class:`canvasapi.file.File` + """ + from canvasapi.file import File + response = self._requester.request( + 'GET', + 'groups/{}/files/{}'.format(self.id, file_id), + **combine_kwargs(**kwargs) + ) + return File(self._requester, response.json()) + def get_full_discussion_topic(self, topic_id): """ Return a cached structure of the discussion topic. diff --git a/canvasapi/user.py b/canvasapi/user.py index 232bbde2..9576c025 100644 --- a/canvasapi/user.py +++ b/canvasapi/user.py @@ -427,6 +427,25 @@ def list_files(self, **kwargs): **combine_kwargs(**kwargs) ) + def get_file(self, file_id, **kwargs): + """ + Return the standard attachment json object for a file. + + :calls: `GET /api/v1/users/:group_id/files/:id \ + `_ + + :param file_id: The ID of the file to retrieve. + :type file_id: int + :rtype: :class:`canvasapi.file.File` + """ + from canvasapi.file import File + response = self._requester.request( + 'GET', + 'users/{}/files/{}'.format(self.id, file_id), + **combine_kwargs(**kwargs) + ) + return File(self._requester, response.json()) + def get_folder(self, folder_id): """ Returns the details for a user's folder diff --git a/tests/fixtures/course.json b/tests/fixtures/course.json index 93ff266b..4a879bc1 100644 --- a/tests/fixtures/course.json +++ b/tests/fixtures/course.json @@ -18,16 +18,16 @@ "status_code": 200 }, "create_folder": { - "method": "POST", - "endpoint": "courses/1/folders", - "data": { - "id": 2, - "name": "Test String", - "locked": false, - "hidden": false - }, - "status_code": 200 - }, + "method": "POST", + "endpoint": "courses/1/folders", + "data": { + "id": 2, + "name": "Test String", + "locked": false, + "hidden": false + }, + "status_code": 200 + }, "create_quiz": { "method": "POST", "endpoint": "courses/1/quizzes", @@ -213,17 +213,17 @@ "status_code": 200 }, "get_folder": { - "method": "GET", - "endpoint": "courses/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": "courses/1/folders/1", + "data": { + "id": 1, + "files_count": 10, + "folders_count": 2, + "name": "Folder 1", + "full_name": "Folder 1" + }, + "status_code": 200 + }, "get_quiz": { "method": "GET", "endpoint": "courses/1/quizzes/1", @@ -382,7 +382,7 @@ "url": "http://example.com/myblog2.rss" } ], - "status_code": 200 + "status_code": 200 }, "list_course_files": { "method": "GET", @@ -422,26 +422,26 @@ "status_code": 200 }, "list_folders": { - "method": "GET", - "endpoint": "courses/1/folders", - "data": [ - { - "id": 2, - "files_count": 0, - "folders_count": 0, - "name": "Folder 2", - "full_name": "course_files/Folder 2" - }, - { - "id": 3, - "files_count": 0, - "folders_count": 0, - "name": "Folder 3", - "full_name": "course_files/Folder 3" - } - ], - "status_code": 200 - }, + "method": "GET", + "endpoint": "courses/1/folders", + "data": [ + { + "id": 2, + "files_count": 0, + "folders_count": 0, + "name": "Folder 2", + "full_name": "course_files/Folder 2" + }, + { + "id": 3, + "files_count": 0, + "folders_count": 0, + "name": "Folder 3", + "full_name": "course_files/Folder 3" + } + ], + "status_code": 200 + }, "list_quizzes": { "method": "GET", "endpoint": "courses/1/quizzes", @@ -926,6 +926,16 @@ }, "status_code": 200 }, + "get_file": { + "method": "GET", + "endpoint": "courses/1/files/1", + "data": { + "id": 1, + "display_name": "Course_File.docx", + "size": 2048 + }, + "status_code": 200 + }, "get_full_discussion_topic": { "method": "GET", "endpoint": "courses/1/discussion_topics/1/view", @@ -1163,20 +1173,20 @@ "endpoint": "courses/1/tabs", "data": [ { - "id": "home", - "html_url": "/courses/1", - "position": 1, - "visibility": "public", - "label": "Home", - "type": "internal" - }, - { - "id": "pages", - "html_url": "/courses/1/wiki", - "position": 2, - "visibility": "public", - "label": "Pages", - "type": "internal" + "id": "home", + "html_url": "/courses/1", + "position": 1, + "visibility": "public", + "label": "Home", + "type": "internal" + }, + { + "id": "pages", + "html_url": "/courses/1/wiki", + "position": 2, + "visibility": "public", + "label": "Pages", + "type": "internal" } ], "status_code": 200 @@ -1267,11 +1277,11 @@ "endpoint": "courses/1/tabs/pages", "data": { "id": "pages", - "html_url": "/courses/1/wiki", - "position": 3, - "visibility": "public", - "label": "Pages", - "type": "internal" + "html_url": "/courses/1/wiki", + "position": 3, + "visibility": "public", + "label": "Pages", + "type": "internal" }, "status_code": 200 }, diff --git a/tests/fixtures/file.json b/tests/fixtures/file.json index 23a0b969..96921634 100644 --- a/tests/fixtures/file.json +++ b/tests/fixtures/file.json @@ -8,5 +8,15 @@ "size": 5512 }, "status_code": 200 + }, + "get_by_id": { + "method": "GET", + "endpoint": "files/1", + "data": { + "id": 1, + "display_name": "File.docx", + "size": 6144 + }, + "status_code": 200 } } diff --git a/tests/fixtures/group.json b/tests/fixtures/group.json index f8811927..0481a4c6 100644 --- a/tests/fixtures/group.json +++ b/tests/fixtures/group.json @@ -608,6 +608,16 @@ }, "status_code": 200 }, + "get_file": { + "method": "GET", + "endpoint": "groups/1/files/1", + "data": { + "id": 1, + "display_name": "Group_File.docx", + "size": 4096 + }, + "status_code": 200 + }, "get_full_discussion_topic": { "method": "GET", "endpoint": "groups/1/discussion_topics/1/view", diff --git a/tests/fixtures/user.json b/tests/fixtures/user.json index fabf08bb..99220a54 100644 --- a/tests/fixtures/user.json +++ b/tests/fixtures/user.json @@ -226,6 +226,16 @@ "name": "John Doe" } }, + "get_file": { + "method": "GET", + "endpoint": "users/1/files/1", + "data": { + "id": 1, + "display_name": "User_File.docx", + "size": 1024 + }, + "status_code": 200 + }, "get_folder": { "method": "GET", "endpoint": "users/1/folders/1", diff --git a/tests/test_canvas.py b/tests/test_canvas.py index a87dd857..cb552a81 100644 --- a/tests/test_canvas.py +++ b/tests/test_canvas.py @@ -12,6 +12,7 @@ from canvasapi.conversation import Conversation from canvasapi.course import Course, CourseNickname from canvasapi.exceptions import RequiredFieldMissing +from canvasapi.file import File from canvasapi.group import Group, GroupCategory from canvasapi.exceptions import ResourceDoesNotExist from canvasapi.progress import Progress @@ -445,6 +446,15 @@ def test_list_group_participants(self, m): groups_list = [group for group in groups] self.assertEqual(len(groups_list), 2) + # get_file() + def test_get_file(self, m): + register_uris({'file': ['get_by_id']}, m) + + file = self.canvas.get_file(1) + self.assertIsInstance(file, File) + self.assertEqual(file.display_name, "File.docx") + self.assertEqual(file.size, 6144) + # search_recipients() def test_search_recipients(self, m): register_uris({'user': ['search_recipients']}, m) diff --git a/tests/test_course.py b/tests/test_course.py index c37815a8..cee7eb1a 100644 --- a/tests/test_course.py +++ b/tests/test_course.py @@ -452,6 +452,15 @@ def test_get_discussion_topic(self, m): self.assertTrue(hasattr(discussion, 'course_id')) self.assertEqual(discussion.course_id, 1) + # get_file() + def test_get_file(self, m): + register_uris({'course': ['get_file']}, m) + + file = self.course.get_file(1) + self.assertIsInstance(file, File) + self.assertEqual(file.display_name, 'Course_File.docx') + self.assertEqual(file.size, 2048) + # get_full_discussion_topic() def test_get_full_discussion_topic(self, m): register_uris({'course': ['get_full_discussion_topic']}, m) diff --git a/tests/test_group.py b/tests/test_group.py index eacebce1..eb171d57 100644 --- a/tests/test_group.py +++ b/tests/test_group.py @@ -211,6 +211,15 @@ def test_get_discussion_topic(self, m): self.assertEqual(group_id, discussion.id) self.assertEqual(discussion.group_id, 1) + # get_file() + def test_get_file(self, m): + register_uris({'group': ['get_file']}, m) + + file = self.group.get_file(1) + self.assertIsInstance(file, File) + self.assertEqual(file.display_name, 'Group_File.docx') + self.assertEqual(file.size, 4096) + # get_full_discussion_topic def test_get_full_discussion_topic(self, m): register_uris({'group': ['get_full_discussion_topic']}, m) diff --git a/tests/test_user.py b/tests/test_user.py index 6241f983..8abc9263 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -277,6 +277,15 @@ def test_user_files(self, m): self.assertEqual(len(file_list), 4) self.assertIsInstance(file_list[0], File) + # get_file() + def test_get_file(self, m): + register_uris({'user': ['get_file']}, m) + + file = self.user.get_file(1) + self.assertIsInstance(file, File) + self.assertEqual(file.display_name, 'User_File.docx') + self.assertEqual(file.size, 1024) + # get_folder() def test_get_folder(self, m): register_uris({'user': ['get_folder']}, m) From 2a617b17eca79098410b477a1720b27fcb033d20 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Mon, 10 Jul 2017 13:10:22 -0400 Subject: [PATCH 10/10] Bumped version to 0.5.0. Added details for 0.5.0 to CHANGELOG.md --- CHANGELOG.md | 13 +++++++++++++ canvasapi/__init__.py | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96265f78..ba3a2218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## [0.5.0] - 2017-07-10 +### New Endpoint Coverage + +- Files (Get file from Canvas, Course, Group, or User) + +### General + +- Added support for Python 3.3, 3.4, 3.5, and 3.6 while maintaining 2.7 compatibility. + +### Bugfixes + +- Fixed an issue where non-ASCII characters in CanvasObject data would throw UnicodeEncodeError exceptions. + ## [0.4.0] - 2017-06-16 ### New Endpoint Coverage diff --git a/canvasapi/__init__.py b/canvasapi/__init__.py index f5af751a..fd2bebb1 100644 --- a/canvasapi/__init__.py +++ b/canvasapi/__init__.py @@ -6,4 +6,4 @@ __all__ = ["Canvas"] -__version__ = '0.4.0' +__version__ = '0.5.0'