Skip to content

Commit

Permalink
Merge pull request #479 from ucfopen/develop
Browse files Browse the repository at this point in the history
Release v2.2.0
  • Loading branch information
Thetwam authored Mar 25, 2021
2 parents a35fea6 + 7ea3566 commit 2ac9979
Show file tree
Hide file tree
Showing 43 changed files with 847 additions and 155 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Deploy to PyPI

on:
push:
tags:
- v[0-9]+.[0-9]+.[0-9]+

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1

- name: Set up Python
uses: actions/setup-python@v2

- name: Create source distribution
run: python setup.py sdist

- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
43 changes: 43 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Run tests

on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests_requirements.txt
- name: Lint with flake8
run: flake8
- name: Check formatting
run: black --check canvasapi tests
- name: Check import sorting
run: isort --check canvasapi tests
- name: Run tests
run: coverage run -m unittest discover
- name: Lint markdown files
uses: bewuethr/mdl-action@v1
- name: Check if methods are alphabetical
run: python scripts/alphabetic.py
- name: Check for missing kwargs
run: python scripts/find_missing_kwargs.py
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
fail_ci_if_error: true
36 changes: 0 additions & 36 deletions .travis.yml

This file was deleted.

8 changes: 7 additions & 1 deletion AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Development Lead
Patches and Suggestions
-----------------------

- Abrahan Nevarez [@zenith110](https://github.com/zenith110)
- Adrian Goetz [@a-goetz](https://github.com/a-goetz)
- Aileen Pongnon [@aileenpongnon](https://github.com/aileenpongnon)
- Alyssa Davis [@allygator](https://github.com/allygator)
Expand All @@ -26,10 +27,12 @@ Patches and Suggestions
- Catherine Abbruzzese [@cat0698](https://github.com/cat0698))
- Cameron Cuff [@ctcuff](https://github.com/ctcuff)
- Dalton Durst [@UniversalSuperBox](https://github.com/UniversalSuperBox)
- Damian Sweeney [@damianfs](https://github.com/damianfs)
- Daniel Brinkman [@DanBrink91](https://github.com/DanBrink91)
- Daniel Grobani [@dgrobani](https://github.com/dgrobani)
- David Warden [@dfwarden](https://github.com/dfwarden)
- Davis Goff [@Goff-Davis](https://github.com/Goff-Davis)
- Deundre Williams [@deundrewilliams](https://github.com/deundrewilliams)
- Devin Singh [@devints47](https://github.com/devints47)
- Dmitry Savransky [@dsavransky](https://github.com/dsavransky)
- Elise Heron [@thedarkestknight](https://github.com/thedarkestknight)
Expand All @@ -42,10 +45,12 @@ Patches and Suggestions
- Ian Altgilbers [@altgilbers](https://github.com/altgilbers)
- Ian Turgeon [@iturgeon](https://github.com/iturgeon)
- [@jackrsteiner](https://github.com/jackrsteiner)
- John Raible [@rebelaide](https://github.com/rebelaide)
- Joon Ro [@joonro](https://github.com/joonro)
- Jonah Majumder [@jonahmajumder](https://github.com/jonahmajumder)
- Jonathan Guilbe [@JonGuilbe](https://github.com/JonGuilbe)
- John Raible [@rebelaide](https://github.com/rebelaide)
- Jose Silveti [@jrsilveti](https://github.com/jrsilveti)
- Joshua Salzedo [@theunkn0wn1](https://github.com/theunkn0wn1)
- Keegan Berry [@keeeeeegan](https://github.com/keeeeeegan)
- Kenny Perez [@kennygperez](https://github.com/kennygperez)
- [@kensler](https://github.com/kensler)
Expand Down Expand Up @@ -77,3 +82,4 @@ Patches and Suggestions
- William Funk [@WilliamRADFunk](https://github.com/WilliamRADFunk)
- William Wesley Monroe [@purpleHey](https://github.com/purpleHey)
- [@wjw27](https://github.com/wjw27)
- Yehuda Davis [@hudcap](https://github.com/hudcap)
26 changes: 25 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

## [Unreleased]

## [2.2.0] - 2021-03-25

### New Endpoint Coverage

- Enroll a user in a section (Thanks, [@damianfs](https://github.com/damianfs))
- File quota for courses, groups, and users (Thanks, [@deundrewilliams](https://github.com/deundrewilliams))
- Provisional Grades (Thanks, [@zenith110](https://github.com/zenith110))

### General

- Added support for Python 3.9
- Added `RateLimitExceeded` exception to distinguish between being rate limited and being otherwise forbidden from accesing a resource. It is a subclass of the `Forbidden` exception.
- File uploads now accept path-like objects (Thanks, [@theunkn0wn1](https://github.com/theunkn0wn1))
- Add list of CanvasAPI Projects to README (Thanks, [@deundrewilliams](https://github.com/deundrewilliams))
- PyPI Package Description now uses README (Thanks, [@bennettscience](https://github.com/bennettscience))
- Replaced Travis CI with GitHub Actions

### Bugfixes

- Fixed an issue where `Canvas.create_poll()` did not work due to an incorrect parameter.
- Canvas.get_todo_items() now correctly returns a `PaginatedList` of `Todo` items (Thanks, [@bennettscience](https://github.com/bennettscience))
- Fixed an issue where `Favorite.remove()` did not handle parameters properly. (Thanks, [@deundrewilliams](https://github.com/deundrewilliams))

## [2.1.0] - 2020-12-04

### New Endpoint Coverage
Expand Down Expand Up @@ -511,7 +534,8 @@ Huge thanks to [@liblit](https://github.com/liblit) for lots of issues, suggesti
- Fixed some incorrectly defined parameters
- Fixed an issue where tests would fail due to an improperly configured requires block

[Unreleased]: https://github.com/ucfopen/canvasapi/compare/v2.1.0...develop
[Unreleased]: https://github.com/ucfopen/canvasapi/compare/v2.2.0...develop
[2.2.0]: https://github.com/ucfopen/canvasapi/compare/v2.1.0...v2.2.0
[2.1.0]: https://github.com/ucfopen/canvasapi/compare/v2.0.0...v2.1.0
[2.0.0]: https://github.com/ucfopen/canvasapi/compare/v1.0.0...v2.0.0
[1.0.0]: https://github.com/ucfopen/canvasapi/compare/v0.16.1...v1.0.0
Expand Down
2 changes: 1 addition & 1 deletion DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ Tag the merge commit with the version number: `git tag -s v0.0.0 -m "Release ve

Push the tag: `git push upstream v0.0.0`

Travis should automatically deploy the tagged code to PyPI.
GitHub Actions should automatically deploy the tagged code to PyPI.

Create release on GitHub for the new tag. Use the text from the changelog for content.
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ CanvasAPI is a Python library for accessing Instructure’s [Canvas LMS API](htt
* [User objects](#user-objects)
* [Paginated Lists](#paginated-lists)
* [Keyword arguments](#keyword-arguments)
* [CanvasAPI Projects](#canvasapi-projects)
* [Contact Us](#contact-us)

## Installation
Expand Down Expand Up @@ -147,14 +148,23 @@ Most of Canvas’s API endpoints accept a variety of arguments. CanvasAPI allows
```python
# Get all of the active courses a user is currently enrolled in
>>> courses = user.get_courses(enrollment_state='active')


# Fetch 50 objects per page when making calls that return a PaginatedList
>>> courses = user.get_courses(per_page=50)
```

For a more detailed description of how CanvasAPI handles more complex keyword arguments, check out the [Keyword Argument Documentation](http://canvasapi.readthedocs.io/en/stable/keyword-args.html).

## CanvasAPI Projects

Since its initial release in June 2016, CanvasAPI has amassed over 100 [dependent repositories](https://github.com/ucfopen/canvasapi/network/dependents). Many of these include various tools used to enhance the Canvas experience for both instructors and students. Here are a few popular repositories that use CanvasAPI:

* [Canvas Grab](https://github.com/skyzh/canvas_grab)
* Canvas Grab is the most popular project using CanvasAPI. This tool, with one click, copies all files from Canvas LMS to local directory. CanvasAPI is used in this project to connect to a course and grab its files.
* [Clanvas](https://github.com/marklalor/clanvas)
* Clanvas is a command-line client for Canvas. It uses the already available bash commands plus some additional ones to interact with various features of Canvas from the commmand line.
* [CS221Bot](https://github.com/Person314159/cs221bot)
* CS221Bot is a Discord bot for the CPCS 221 course at University of British Columbia. CanvasAPI is used in this project to connect to and synchronize with a course and get its data, such as announcements, new assignments, and more.

If you have a project that uses CanvasAPI that you'd like to promote, please contact us!

## Contact Us

Need help? Have an idea? Just want to say hi? Come join us on the [UCF Open Slack Channel](https://ucf-open-slackin.herokuapp.com) and join the `#canvasapi` channel!
Need help? Have an idea? Feel free to check out our [Discussions](https://github.com/ucfopen/canvasapi/discussions) board. Just want to say hi or get extended spport? Come join us on the [UCF Open Slack Channel](https://ucf-open-slackin.herokuapp.com) and join the `#canvasapi` channel!
2 changes: 1 addition & 1 deletion canvasapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

__all__ = ["Canvas"]

__version__ = "2.1.0"
__version__ = "2.2.0"
109 changes: 104 additions & 5 deletions canvasapi/assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from canvasapi.peer_review import PeerReview
from canvasapi.progress import Progress
from canvasapi.submission import Submission
from canvasapi.upload import Uploader
from canvasapi.upload import FileOrPathLike, Uploader
from canvasapi.user import User, UserDisplay
from canvasapi.util import combine_kwargs, obj_or_id

Expand Down Expand Up @@ -160,6 +160,32 @@ def get_peer_reviews(self, **kwargs):
_kwargs=combine_kwargs(**kwargs),
)

def get_provisional_grades_status(self, student_id, **kwargs):
"""
Tell whether the student's submission needs one or more provisional grades.
:calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/provisional_grades/
status \
<https://canvas.instructure.com/doc/api/all_resources.html#method.provisional_grades.status>`_
:param student_id: The object or ID of the related student
:type student_id: :class:`canvasapi.user.User` or int
:rtype: bool
"""
kwargs["student_id"] = obj_or_id(student_id, "student_id", (User,))
request = self._requester.request(
"GET",
"courses/{}/assignments/{}/provisional_grades/status".format(
self.course_id, self.id
),
_kwargs=combine_kwargs(**kwargs),
)

request_json = request.json()

return request_json.get("needs_provisional_grade")

def get_submission(self, user, **kwargs):
"""
Get a single submission, based on user id.
Expand Down Expand Up @@ -205,6 +231,55 @@ def get_submissions(self, **kwargs):
_kwargs=combine_kwargs(**kwargs),
)

def publish_provisional_grades(self, **kwargs):
"""
Publish the selected provisional grade for all submissions to an assignment.
Use the “Select provisional grade” endpoint to choose which provisional grade to publish
for a particular submission.
Students not in the moderation set will have their one
and only provisional grade published.
WARNING: This is irreversible. This will overwrite existing grades in the gradebook.
:calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/provisional_grades
/publish \
<https://canvas.instructure.com/doc/api/all_resources.html#method.provisional_grades.publish>`_
:rtype: dict
"""
response = self._requester.request(
"POST",
"courses/{}/assignments/{}/provisional_grades/publish".format(
self.course_id, self.id
),
_kwargs=combine_kwargs(**kwargs),
)
return response.json()

def selected_provisional_grade(self, provisional_grade_id, **kwargs):
"""
Choose which provisional grade the student should receive for a submission.
The caller must be the final grader for the assignment
or an admin with :select_final_grade rights.
:calls: `PUT /api/v1/courses/:course_id/assignments/:assignment_id/provisional_grades/
:provisonal_grade_id/select \
<https://canvas.instructure.com/doc/api/all_resources.html#method.provisional_grades.select>`_
:param provisional_grade_id: ID of the provisional grade
:type provisional_grade_id: int
:rtype: dict
"""
response = self._requester.request(
"PUT",
"courses/{}/assignments/{}/provisional_grades/{}/select".format(
self.course_id, self.id, provisional_grade_id
),
_kwargs=combine_kwargs(**kwargs),
)

return response.json()

def set_extensions(self, assignment_extensions, **kwargs):
"""
Set extensions for student assignment submissions
Expand All @@ -222,11 +297,11 @@ def set_extensions(self, assignment_extensions, **kwargs):
>>> assignment.set_extensions([
... {
... 'user_id': 3,
... 'extra_attempts: 2
... 'extra_attempts': 2
... },
... {
... 'user_id': 2,
... 'extra_attempts: 2
... 'extra_attempts': 2
... }
... ])
"""
Expand Down Expand Up @@ -254,6 +329,30 @@ def set_extensions(self, assignment_extensions, **kwargs):
for extension in extension_list
]

def show_provisonal_grades_for_student(self, anonymous_id, **kwargs):
"""
:call: `GET /api/v1/courses/:course_id/assignments/:assignment_id/
anonymous_provisional_grades/status \
<https://canvas.instructure.com/doc/api/all_resources.html#method.anonymous_provisional_grades.status>`_
:param anonymous_id: The ID of the student to show the status for
:type anonymous_id: :class:`canvasapi.user.User` or int
:rtype: dict
"""

kwargs["anonymous_id"] = obj_or_id(anonymous_id, "anonymous_id", (User,))

request = self._requester.request(
"GET",
"courses/{}/assignments/{}/anonymous_provisional_grades/status".format(
self.course_id, self.id
),
_kwargs=combine_kwargs(**kwargs),
)

return request.json().get("needs_provisional_grade")

def submissions_bulk_update(self, **kwargs):
"""
Update the grading and comments on multiple student's assignment
Expand Down Expand Up @@ -318,7 +417,7 @@ def submit(self, submission, file=None, **kwargs):

return Submission(self._requester, response_json)

def upload_to_submission(self, file, user="self", **kwargs):
def upload_to_submission(self, file: FileOrPathLike, user="self", **kwargs):
"""
Upload a file to a submission.
Expand All @@ -327,7 +426,7 @@ def upload_to_submission(self, file, user="self", **kwargs):
<https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.create_file>`_
:param file: The file or path of the file to upload.
:type file: file or str
:type file: FileLike
:param user: The object or ID of the related user, or 'self' for the
current user. Defaults to 'self'.
:type user: :class:`canvasapi.user.User`, int, or str
Expand Down
Loading

0 comments on commit 2ac9979

Please sign in to comment.