A Canvas course management tool
Project description
Easel
A Canvas course management tool.
Installation
pip install easel-cli
To install from the root of the repository:
pip install -e .
Usage
When connected to a Canvas course, easel will read in a yaml file and create the
corresponding component in Canvas on that course. Currently, easel requires you
to run its commands from the root of your course directory (where the component
subdirectories are located). This is where easel will initialize its database:
.easeldb
.
Getting Started
For each of these operations, refer to their detailed description and usage below.
- Tell easel about your Canvas instance (only needs to be run once):
easel login <canvas_base_url> <api_token>
- Initialize easel in a course-specific directory:
easel init
- Add a course or courses (i.e., sections):
easel course add <canvas_course_url>
- Create yaml files describing your course content and push them to your
course:
easel push [component_filepath ...]
Easel makes it easy to not have to start from scratch by first pulling the material from a previous course and pushing it to a new course:
- Tell easel about your Canvas instance:
easel login <canvas_base_url> <api_token>
- Initialize easel in a course-specific directory:
easel init
- Add the previous course:
easel course add <previous_canvas_course_url>
- Pull everything from it:
easel pull
- Add the new course:
easel course add <new_canvas_course_url>
- Push everything to the new course:
easel --course <new_course_id> push
- At this point, you may remove your old course:
easel course remove <old_course_id>
Individual Component References
These are the components currently managed by easel. For configuration, see the linked documentation.
- Assignments
- Assignment Groups
- External Tools
- Course Grading Scheme
- Course Settings
- Modules
- Navigation Tabs
- Pages
- Quizzes
- Syllabus
Command Reference
Login
easel login <canvas_base_url> <api_token>
E.g.,
easel login https://school.instructure.com yourT0kenH3re
Only needs to be run once per client machine. Records the Canvas url and token to be used later. Canvas tokens can be generated in "Account->Settings->+New Access Token".
Init
easel init
Run this one time per course directory. It will initialize the easel database in the current directory. It will also create subdirectories for each Canvas component type that easel supports.
At this time, easel requires components to be organized by directory but this is hopefully a temporary restriction.
Course
easel course add <canvas_course_url>
E.g.,
easel course add https://school.instructure.com/courses/615446
Hooks up the database to a Canvas course. Run this one time per Canvas course (once per section taught per semester).
easel course list
List all Canvas courses that are tracked in the database.
Push
Reads in and pushes a specific component (or multiple components) to the configured courses. A push reads the information of each component stored locally and for each one, makes a POST or PUT request to Canvas, depending on whether you are creating or updating the component in the Canvas course.
easel push
or to push to a specific course:
easel --course <course_id> push
To push a specific component or components:
easel push [component_filepath ...]
E.g.,
easel push pages/lesson-1.yaml
Notes on pushing files:
- Files placed in the
files
directory will be pushed as they are (ignoring thefiles
parent directory). - Supports multiple filename arguments and wildcards for batch pushing.
- Use the
--hidden
flag to unpublish the file(s) as hidden when pushed (by default canvas publishes files when you upload them). - When pushing a directory,
easel
will push all of its child files.
Course filtering:
Use the --course
flag (alternatively -c
) to specify a subset of your
courses. I prefer to use the section number to identify a course. For example,
to push a page to only sections 01 and 02, I would use this command:
easel push -c 01 -c 02 pages/lesson-1.yaml
Remove
Remove a given component(s) from the canvas course. This does not delete the yaml file or the local database entry for the component. But it will remove the database record which tracks that component in Canvas (i.e., it's Canvas ID).
easel remove [component_filepath ...]
E.g.,
easel remove pages/lesson-1.yaml
Note for files:
- Supports multiple filename arguments and wildcards for batch removing.
- When removing a directory,
easel
will remove all of its child files (however the empty directory will remain in Canvas).
File Structure
For now it is required to store component files in separate directories, named
for their component type (e.g., store definition files for pages in a directory
called pages
). This requirement may be removed in the future.
Each individual component is defined by a single file using yaml. When a
component has some associated body/description content, it should be included in
markdown as part of the component's yaml configuration using a multiline string
(see the examples
directory for examples).
Dates
When specifying dates (e.g., due_at, unlock_at, lock_at), ISO 8601 format should be used. This is temporary until I can build out an internal date management system.
TODO
I'll try to keep this list in order, with the items I'm prioritizing to get done sooner listed first.
- add a new command which generates a component config file formatted and filled
with common options
- -i flag could prompt user to enter required options interactively
- manage datetimes for user
- relative semester/time specification
- e.g.,
- module 1 day 2 start of class,
- module 6 class 1 start of class,
- week 4 day -1 end of class
- start of week 2 (first day of the week in the morning)
- end of week 3 (last day of the week at midnight)
- instead of weeks use modules?
- define module with respect to 150-minute chunks (equivalent of one week)
- gives us more flexibility for holidays
- user specifies dependency tree for modules in terms of prerequisite modules
- easel schedules the modules based on semester dates
- deadlines are declared with respect to the module (which may carry over to another week, depending on holidays, etc.
- fields
- due_at
- detect if already in iso format and if not, parse as the relative formate
- length (for modules only)
- the number of 50 minute blocks in this module
- previous module?
- next module?
- due_at
- implementation
- detect semester dates
- start and end dates (including finals?)
- holidays
- map modules to the semester based on module length and semester dates
- if no modules, just use weeks
- detect semester dates
- e.g.,
- API requires strings in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ (e.g., "2013-01-23T23:59:00-07:00")
- automate daylight savings translations
- maybe consider automating final exam times too
- relative semester/time specification
- test other types of module items
- working:
- Page
- Assignment
- File
- SubHeader
- ExternalUrl
- need testing:
- Discussion
- Quiz
- pulls down as an assignment?
- ExternalTool
- working:
- better logging
- I've been assuming user pulls or pushes from the course's root directory. Need to search for the component dirs
- Figure out the workflow for editing page/assignment content. Canvas uses html,
I'd prefer to express it in markdown.
- First proposal: locally in markdown, convert to html when pushing. Don't edit content in Canvas (since we can't faithfully convert html to md). Pulling would not overwrite the component's contents.
- multiple courses (i.e., sections).
- implicit iteration
- push: pushes to all courses, unless specified (e.g., -c 02)
- pull: pulls from all courses, checks for and reports any differences
- need to add a prompt for overwrite, manually merge, or abort
- implicit iteration
- pull/push everything in transactions
- use db as intermediate step, only go to Canvas if db transaction succeeded
- workflow for pulling whether to overwrite, manually merge, or abort
- When pushing, update database with result (e.g., when pushing to a new course, the canvas id will be different)
- merge prompt
- add a progress bar for pushing and pulling
- add a command to publish components rather than changing the published field in the file?
- GUI?
- support Formula type quiz questions. it's almost there but it probably
requires the weird json list formatting as with QuizQuestion.answers. See the
TODO comment in
__iter__
fromquiz_question.py
- delete folders
- since I don't explicitly create folders, I don't have their ids, so I'd have to get that at some point and track it to eventually delete it
- https://canvas.instructure.com/doc/api/files.html#method.folders.api_destroy
- auto generate syllabus parts
Thoughts
- Enforce directories? (e.g., pages, assignments, modules)
- Or when pushing a component, save its filepath in the db
- Component files that only have yaml (no md or html), should the extension be yaml or stay consistent with md?
- We should enable expressing dates/times that are relative to the section meeting time (e.g., beginning of class, end of class, Fridays)
- would it be worth adding in grading stuff eventually?
- Some fields would be useful to Easel but not necessary for instructor edits (e.g., record ids, component status). Do we keep those in the DB but not write them to file?
- should quiz questions be in their own file? Options:
- a single quiz's questions in one file. easier to implement but it would be harder to reuse them
- one file per question, easy to move around, but how to uniquely identify each question? (for the name of the file)
- one file per question category (e.g., all requrements engineering questions) this is probably the best user-focused approach, but harder to implement?
- Question groups only work with question banks. We can't create question banks
via the api. What other option do we have? Ideally we create a question group
directly with the questions that should go in it. E.g.,
The preprocessor would intercept the- question_name: g1 question_type: group questions: - quiz_questions/functions.yaml - quiz_questions/functions.yaml - quiz_questions/functions.yaml
question_type
(it's invalid anyway) and make the api call to create the group, passing in the questions. So remember that in case they open up question groups to work by specifying a question directly. - by default, canvas courses do not enable weighted assignment groups
- allow users to update the course with this (or make it the default?)
- I set it up for now to automatically weight (default to True in push_syllabus of course.py)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file easel-cli-1.1.1.tar.gz
.
File metadata
- Download URL: easel-cli-1.1.1.tar.gz
- Upload date:
- Size: 49.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0a7e6ef286586b9d4ec930d0f77f35c78b8c95f6867066543fe105f7e839c84a |
|
MD5 | 219d349d1457b0d6bfce9e1282aea7ac |
|
BLAKE2b-256 | a57d0c30171b19f689cd7f52679e04b52a1f897b4197cea7f7feb3316329f9c3 |
File details
Details for the file easel_cli-1.1.1-py3-none-any.whl
.
File metadata
- Download URL: easel_cli-1.1.1-py3-none-any.whl
- Upload date:
- Size: 53.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 15ee720f0d8adb4d10e7436a111b1ea3c96c34cfe8abb83b838a27f7116fce70 |
|
MD5 | a06e2fd63a7b765a73839165eb99aaa1 |
|
BLAKE2b-256 | c534f7d44e768ceddbdd276b8d63007565bcf95766d97e9af79dd4c007840d7c |