Skip to content

Commit 5c0884b

Browse files
author
Kevin Hansen
committed
add Makefile for testing and updated README.rst
1 parent 36ca331 commit 5c0884b

File tree

7 files changed

+96
-18
lines changed

7 files changed

+96
-18
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ __pycache__
33
*egg-info*
44
*.eggs
55
/dist/
6+
.cache

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test:
2+
nosetests tests

README.rst

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,112 @@
11
py_canvas_api
2-
=============
2+
#############
33

44
The idea is to have a simple, easy to understand library for the Canvas API.
55

66
The Canvas API (https://canvas.instructure.com/doc/api/index.html) has hundreds of endpoints.
7+
78
It seemed pointless to me to write a unique method for every one of them.
89
Instead, I created a class, called `ResterAPI` that uses `__getattr__` to
9-
dynamically generate the URLS for an endpoint and `__call__` to make the actual
10-
request. The `Canvas` class is built on top of `ResterAPI`.
10+
dynamically generate the path for an endpoint and `__call__` to add a path
11+
element with a parameter. The `Canvas` class is built on top of `ResterAPI`.
1112

1213
The result is a fairly small library that can handle the vast majority of
13-
Canvas API endpoints. There are a few unique cases that are addressed in special
14-
classes. For example, the `SIS Import API`_ takes a file upload and needs
15-
special handling.
14+
Canvas API endpoints.
1615

17-
Here is how to do an SIS Import.
16+
17+
Instantiate the Canvas object like this.
1818

1919
.. code-block:: py
2020
21-
from canvas_api import SISImporter
22-
sis_importer = SISImporter('somedomain.instructure.com', CANVAS_ACCESS_TOKEN=os.getenv('ACCESS_TOKEN'))
23-
sis_importer.do_sis_import(filepath)
21+
from canvas_api import Canvas
22+
c = Canvas('somedomain.instructure.com', CANVAS_ACCESS_TOKEN=os.getenv('ACCESS_TOKEN'))
2423
2524
26-
Instantiate the Canvas object like this.
25+
Building paths
26+
==============
27+
You build the path appending "methods" after the instanted canvas_api object.
28+
29+
You will typically see a line like `GET /api/v1/accounts/:account_id/courses`
30+
in the Canvas API documentation. This tells you what the path is and the inline
31+
parameters it needs. You would build this path with the `py_canvas_api` library
32+
like this: `c.accounts(8423).courses`. Don't worry about the `/api/v1` part.
33+
34+
The `py_canvas_api` library takes care of the path parameters like :user by taking
35+
them as method arguments. For example, here is how you would get courses in the
36+
account with the id of 10 using the path above.
37+
38+
.. code-block:: py
39+
40+
# get a list of courses (paginated to 10) in the account
41+
accounts = c.accounts('self').courses.get().json()
42+
43+
Common Requests
44+
================
45+
46+
GET
47+
-----
48+
49+
To make a `GET` request, simply end with `get()`. This tells the library to
50+
make a GET request. This library uses the awesome `Requests`_ library so the
51+
return object in this case is simple a Response object. You will most often
52+
want the response as a json object. You get this by calling .json() with the
53+
Response.
54+
55+
.. code-block:: py
56+
57+
# get a list of courses (paginated to 10) in the account
58+
accounts_json = c.accounts('self').courses.get().json()
59+
60+
If you need to send query parameters (key-value pairs added after a question
61+
mark), add these as keyword parameters in the `get()` call. Let's say you want
62+
a list of your own courses where you are a teacher and the enrollment is active. You would normally need to
63+
add `?enrollment_type=teacher&enrollment_state=active` to the URL to do this. With the `py_canvas_api`
64+
library, however, you would do it like this.
2765

2866
.. code-block:: py
2967
30-
from canvas_api import Canvas
31-
c = Canvas('somedomain.instructure.com', CANVAS_ACCESS_TOKEN=os.getenv('ACCESS_TOKEN'))
3268
# get a list of courses (paginated to 10) in the account
33-
accounts = c.accounts('self').courses.get()
69+
accounts_json = c.courses.get(enrollment_type='teacher', enrollment_state='active').json()
70+
71+
Here are several more `GET` examples.
72+
73+
.. code-block:: py
74+
75+
# list of users
76+
users = c.accounts('self').users.get().json()
77+
78+
# assignments in course with canvas id 23423
79+
assignments = c.courses(23423).assignments.get().json()
80+
81+
# assignments in course with sis id ENG101
82+
assignments = c.courses('sis_course_id:ENG101').assignments.get().json()
83+
84+
# list communication channels for user with id 82
85+
channels = c.users(82).communication_channels.get().json()
86+
87+
# list own communication channels
88+
channels = c.users('self').communication_channels.get().json()
3489
3590
# Get a list of all courses in the account. This will keep pulling results as
3691
# long as there are more pages. It uses generator functions to do this is a
3792
# smart way.
3893
accounts = c.accounts('self').course.get_paginated()
3994
95+
Special Cases
96+
==============
97+
There are a few unique cases that are addressed in special
98+
classes. For example, the `SIS Import API`_ takes a file upload and needs
99+
special handling.
100+
101+
Here is how to do an SIS Import.
102+
103+
.. code-block:: py
104+
105+
from canvas_api import SISImporter
106+
sis_importer = SISImporter('somedomain.instructure.com', CANVAS_ACCESS_TOKEN=os.getenv('ACCESS_TOKEN'))
107+
sis_importer.do_sis_import(filepath)
108+
40109
41110
.. _`SIS Import API`: https://canvas.instructure.com/doc/api/sis_imports.html
111+
112+
.. _`Requests`: http://docs.python-requests.org/en/master/

py_canvas_api/canvas_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import collections
55
import mimetypes
66
from .rester_api import ResterAPI, Paginates
7+
from .common import log
78

89
class Canvas(ResterAPI, Paginates):
910

py_canvas_api/commons.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# -*- coding: utf-8 -*-
22
import requests
3+
import json
34
from .rester_api import ResterAPI, log
5+
from .canvas_api import Canvas
46

57
class Commons(ResterAPI):
68
def __init__(self, base_url, *args, **kwargs):

py_canvas_api/rester_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22
import requests
3+
import json
34
from .common import log
45

56
class ResterAPI(object):

tests/test_init_canvas.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import json
1010
import requests
1111

12-
import canvas_api
12+
from py_canvas_api import canvas_api
13+
1314
BASE_URL = 'kevin.test.instructure.com'
1415
CANVAS_ACCESS_TOKEN='1~7GxKeS9cqHcNQxzKAZBhot6qurrWsJrYhPJiTY71lqxj37peuccu0ESl4fXh1VRL'
1516

@@ -55,13 +56,13 @@ def test_upload_file(self):
5556
# TODO how do I mock this?
5657
pass
5758

59+
from py_canvas_api import commons
5860
class TestCommonsAPI(TestCase):
5961
def setUp(self):
60-
self.commons = canvas_api.Commons(BASE_URL, CANVAS_ACCESS_TOKEN=CANVAS_ACCESS_TOKEN)
62+
self.commons = commons.Commons(BASE_URL, CANVAS_ACCESS_TOKEN=CANVAS_ACCESS_TOKEN)
6163
self.jwt_response = { "jwt_token": "eyJ0eXAiOiJ"}
6264
self.session_response = { "sessionId": u"lkjlklkjlkj"}
6365

64-
#self.commons.canvas2.req = MagicMock()
6566
res_list = json.load(open(os.path.join(BASE_DIR, 'resources_list.json'),'rU'))
6667
requests.get = MagicMock()
6768
requests.get.side_effect = [
@@ -74,7 +75,6 @@ def setUp(self):
7475
MagicMock(status_code=200, text=json.dumps(self.session_response), json=lambda: self.session_response)
7576
]
7677

77-
7878
def test_get_jwt_token(self):
7979
jwt_token = self.commons.get_jwt_token()
8080
assert jwt_token == self.jwt_response

0 commit comments

Comments
 (0)