canvas-term 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- canvas_term-0.2.0/LICENSE +21 -0
- canvas_term-0.2.0/PKG-INFO +279 -0
- canvas_term-0.2.0/README.md +241 -0
- canvas_term-0.2.0/canvas_cli/__init__.py +3 -0
- canvas_term-0.2.0/canvas_cli/api.py +260 -0
- canvas_term-0.2.0/canvas_cli/cli.py +631 -0
- canvas_term-0.2.0/canvas_cli/config.py +160 -0
- canvas_term-0.2.0/canvas_cli/errors.py +27 -0
- canvas_term-0.2.0/canvas_term.egg-info/PKG-INFO +279 -0
- canvas_term-0.2.0/canvas_term.egg-info/SOURCES.txt +18 -0
- canvas_term-0.2.0/canvas_term.egg-info/dependency_links.txt +1 -0
- canvas_term-0.2.0/canvas_term.egg-info/entry_points.txt +2 -0
- canvas_term-0.2.0/canvas_term.egg-info/requires.txt +12 -0
- canvas_term-0.2.0/canvas_term.egg-info/top_level.txt +1 -0
- canvas_term-0.2.0/pyproject.toml +81 -0
- canvas_term-0.2.0/setup.cfg +4 -0
- canvas_term-0.2.0/tests/test_api.py +225 -0
- canvas_term-0.2.0/tests/test_cli.py +322 -0
- canvas_term-0.2.0/tests/test_config.py +121 -0
- canvas_term-0.2.0/tests/test_token_leaks.py +75 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Linux-Viking
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: canvas-term
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A command-line interface for Canvas LMS: grades, to-dos, discussions, file downloads, and assignment submission.
|
|
5
|
+
Author: Linux-Viking
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Linux-Viking/canvas-cli
|
|
8
|
+
Project-URL: Issues, https://github.com/Linux-Viking/canvas-cli/issues
|
|
9
|
+
Project-URL: Source, https://github.com/Linux-Viking/canvas-cli
|
|
10
|
+
Keywords: canvas,canvas-lms,instructure,lms,cli,students
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Education
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Education
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: click>=8.1
|
|
27
|
+
Requires-Dist: requests>=2.32
|
|
28
|
+
Requires-Dist: keyring>=24
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
31
|
+
Requires-Dist: responses>=0.25; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
33
|
+
Requires-Dist: black>=24; extra == "dev"
|
|
34
|
+
Requires-Dist: isort>=5.13; extra == "dev"
|
|
35
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
36
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# canvas-cli
|
|
40
|
+
|
|
41
|
+
[](https://github.com/Linux-Viking/canvas-cli/actions/workflows/ci.yml)
|
|
42
|
+
|
|
43
|
+
A lightning-fast, terminal-based operating system for your degree.
|
|
44
|
+
|
|
45
|
+
`canvas-cli` is a command-line interface for the Canvas Learning Management System (LMS). It lets students check grades, view upcoming assignments, take part in discussion boards, bulk-download course files, and submit assignments (PDFs, documents, code) from the terminal without opening a web browser.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
* **Submissions**: Upload local files directly to assignments using Canvas's native 3-step upload protocol, with automatic post-submission verification.
|
|
50
|
+
* **To-Do List**: View upcoming assignments and due dates across all active courses.
|
|
51
|
+
* **Grades**: Check your current score and letter grade for every course.
|
|
52
|
+
* **Discussion Boards**: Read prompts and replies, and post top-level or threaded replies.
|
|
53
|
+
* **Bulk File Downloader**: Download all slides, syllabi, and readings from a course with one command.
|
|
54
|
+
* **Inbox**: Read your unread Canvas messages.
|
|
55
|
+
* **Aliases**: Map Canvas IDs (like `123456`) to memorable names (like `cs101`).
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
Requires **Python 3.11 or newer**.
|
|
60
|
+
|
|
61
|
+
### Recommended: pipx
|
|
62
|
+
|
|
63
|
+
[pipx](https://pipx.pypa.io/) installs the CLI into its own isolated environment and puts `canvas-cli` on your `PATH`.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pipx install git+https://github.com/Linux-Viking/canvas-cli.git
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Once it's published on PyPI, it will be:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pipx install canvas-term
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
> The PyPI package is named **`canvas-term`** (`canvas-cli` is taken by an unrelated project), but the command it installs is still **`canvas-cli`**.
|
|
76
|
+
|
|
77
|
+
### pip
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python3 -m pip install --user git+https://github.com/Linux-Viking/canvas-cli.git
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Upgrading and uninstalling
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pipx upgrade canvas-term
|
|
87
|
+
pipx uninstall canvas-term
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Configuration
|
|
91
|
+
|
|
92
|
+
### 1. Generate an API token
|
|
93
|
+
|
|
94
|
+
1. Log into your school's Canvas website.
|
|
95
|
+
2. Click **Account** (your profile picture) → **Settings**.
|
|
96
|
+
3. Scroll to **Approved Integrations** and click **+ New Access Token**.
|
|
97
|
+
4. Give it a purpose (e.g. `canvas-cli`), optionally an expiry date, and click **Generate Token**.
|
|
98
|
+
5. Copy the token immediately. Canvas won't show it again.
|
|
99
|
+
|
|
100
|
+
### 2. Configure the CLI
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
canvas-cli config
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
You'll be prompted for:
|
|
107
|
+
|
|
108
|
+
* **Canvas Domain**: your school's Canvas URL, e.g. `https://school.instructure.com`. Must be `https://`; a bare hostname is fine.
|
|
109
|
+
* **Canvas API Token**: paste the token. Input is hidden.
|
|
110
|
+
|
|
111
|
+
The CLI then checks the token by asking Canvas who you are:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
Configuration saved for https://school.instructure.com.
|
|
115
|
+
Verifying token...
|
|
116
|
+
Logged in as Ada Lovelace.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Re-run `canvas-cli config` whenever your token expires. Your aliases are kept.
|
|
120
|
+
|
|
121
|
+
#### Non-interactive setup
|
|
122
|
+
|
|
123
|
+
The token is deliberately **not** accepted as a command-line argument, because arguments end up in shell history and process listings. For scripts, pipe it on stdin:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
pass show canvas/token | canvas-cli config --url https://school.instructure.com --token-stdin
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Using an environment variable instead of the keyring
|
|
130
|
+
|
|
131
|
+
If `CANVAS_TOKEN` is set, it takes priority over the keyring. This is useful on servers, in containers, or where no keyring is available:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
export CANVAS_TOKEN="$(pass show canvas/token)"
|
|
135
|
+
canvas-cli grades
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Where things are stored
|
|
139
|
+
|
|
140
|
+
| What | Where |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| API token | Your OS keyring (macOS Keychain, Windows Credential Locker, or Linux Secret Service such as GNOME Keyring or KWallet), or `$CANVAS_TOKEN` |
|
|
143
|
+
| Canvas URL and aliases | `~/.canvas_cli.json` (permissions `0600`, never contains the token) |
|
|
144
|
+
|
|
145
|
+
## Usage
|
|
146
|
+
|
|
147
|
+
Every command and group accepts `-h`, `--help`, or a trailing `help`:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
canvas-cli help
|
|
151
|
+
canvas-cli course help
|
|
152
|
+
canvas-cli submit -h
|
|
153
|
+
canvas-cli --version
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Courses, modules, and items
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
canvas-cli list # active courses and their IDs
|
|
160
|
+
canvas-cli course 123456 list # modules in a course
|
|
161
|
+
canvas-cli course 123456 module 7890 list # items in a module
|
|
162
|
+
canvas-cli course 123456 module 7890 item 555 details # item info + assignment description
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Aliases
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
canvas-cli alias set cs101 123456
|
|
169
|
+
canvas-cli course cs101 list
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Aliases work anywhere a course, module, item, assignment, or topic ID is expected.
|
|
173
|
+
|
|
174
|
+
### Grades, to-dos, and inbox
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
canvas-cli grades
|
|
178
|
+
canvas-cli todo
|
|
179
|
+
canvas-cli inbox list
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Submitting an assignment
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
canvas-cli submit ./my_essay.pdf cs101 987654
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
You'll see a pre-submission summary and must confirm. After uploading, the CLI asks Canvas to confirm that the submission was received and the file is attached.
|
|
189
|
+
|
|
190
|
+
> **Find the assignment ID** with `canvas-cli course <course> module <module> item <item> details`, which prints the exact `submit` command to run.
|
|
191
|
+
|
|
192
|
+
### Discussions
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# List topics, then read a topic and its replies
|
|
196
|
+
canvas-cli course cs101 discuss list
|
|
197
|
+
canvas-cli course cs101 discuss view 555123
|
|
198
|
+
|
|
199
|
+
# Read the threaded replies under one entry
|
|
200
|
+
canvas-cli course cs101 discuss view 555123 --entry-id 999888
|
|
201
|
+
|
|
202
|
+
# Reply to the main prompt (\n becomes a line break)
|
|
203
|
+
canvas-cli course cs101 discuss reply 555123 "Here is my response...\nSecond paragraph."
|
|
204
|
+
|
|
205
|
+
# Reply from a file (newlines are preserved)
|
|
206
|
+
canvas-cli course cs101 discuss reply 555123 --file ./response.md
|
|
207
|
+
|
|
208
|
+
# Threaded reply to a specific student
|
|
209
|
+
canvas-cli course cs101 discuss reply 555123 "I agree!" --entry-id 999888
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Downloading course files
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
canvas-cli course cs101 files download # saves to ./course_<id>_files/
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Errors and troubleshooting
|
|
219
|
+
|
|
220
|
+
Commands exit with status `0` on success and non-zero on failure, so you can use them in scripts.
|
|
221
|
+
|
|
222
|
+
| Message | What to do |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| `No API token configured` | Run `canvas-cli config`. |
|
|
225
|
+
| `Canvas rejected your API token (401 Unauthorized)…` | Your token expired or was revoked. Generate a new one and run `canvas-cli config`. |
|
|
226
|
+
| `Canvas is rate limiting requests…` | The CLI already retried with backoff. Wait a minute and try again. |
|
|
227
|
+
| `Could not connect to …` / `… timed out` | Check your network connection and Canvas URL. Read-only requests are retried automatically. Submissions and replies are **never** retried automatically, so they can't be posted twice. |
|
|
228
|
+
| `Permission denied (403)` | Your account doesn't have access to that resource (e.g. the course is concluded or the item is locked). |
|
|
229
|
+
| `Not found (404)` | Check the ID or alias. In `module list`, use the ID shown in the first column. |
|
|
230
|
+
| `Canvas URL must use https://` | Re-run `canvas-cli config` with an `https://` URL. |
|
|
231
|
+
|
|
232
|
+
### Keyring troubleshooting (Linux)
|
|
233
|
+
|
|
234
|
+
`canvas-cli` uses the [`keyring`](https://pypi.org/project/keyring/) library. On a desktop with GNOME Keyring or KWallet running, it works out of the box. On headless servers, WSL, or minimal installs, there may be no keyring service:
|
|
235
|
+
|
|
236
|
+
* **`Could not read/save the API token to the system keyring`**: either start a Secret Service provider (e.g. `gnome-keyring-daemon`) or use the `CANVAS_TOKEN` environment variable.
|
|
237
|
+
* **Warning about a plain-text keyring backend**: some setups fall back to `keyrings.alt`, which stores secrets unencrypted on disk. `canvas-cli config` warns you if so. Prefer a real keyring or `CANVAS_TOKEN`.
|
|
238
|
+
* Run `pipx run keyring --list-backends` to see which keyring backends are available.
|
|
239
|
+
|
|
240
|
+
## Security
|
|
241
|
+
|
|
242
|
+
* Your API token is stored only in the OS keyring (or read from `$CANVAS_TOKEN`). It is never written to the config file, accepted as a command-line argument, or printed in output. Error messages are redacted.
|
|
243
|
+
* The token is sent only over `https://`, and only to your configured Canvas host. File downloads and uploads to external storage (e.g. S3) never receive it.
|
|
244
|
+
* Treat your token like a password: it grants full access to your Canvas account. Set an expiry date when you generate it and revoke it in Canvas settings if it's ever exposed.
|
|
245
|
+
|
|
246
|
+
Found a security issue? Please open a private [security advisory](https://github.com/Linux-Viking/canvas-cli/security/advisories/new) rather than a public issue.
|
|
247
|
+
|
|
248
|
+
## Development
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
git clone https://github.com/Linux-Viking/canvas-cli.git
|
|
252
|
+
cd canvas-cli
|
|
253
|
+
python3 -m venv .venv
|
|
254
|
+
source .venv/bin/activate
|
|
255
|
+
pip install --editable ".[dev]"
|
|
256
|
+
|
|
257
|
+
pytest # run the test suite (no network or real keyring needed)
|
|
258
|
+
ruff check . # lint
|
|
259
|
+
black . && isort . # format
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
CI runs linting, tests on Python 3.11–3.14 (plus macOS and Windows), a build and `pipx install` smoke test, and a [gitleaks](https://github.com/gitleaks/gitleaks) secret scan of the full git history.
|
|
263
|
+
|
|
264
|
+
### Releasing
|
|
265
|
+
|
|
266
|
+
Releases are published to PyPI by `.github/workflows/publish.yml` using [trusted publishing](https://docs.pypi.org/trusted-publishers/), so no PyPI API token is stored anywhere.
|
|
267
|
+
|
|
268
|
+
1. Bump `__version__` in `canvas_cli/__init__.py`.
|
|
269
|
+
2. Create a GitHub release tagged `v<version>` (e.g. `v0.2.0`).
|
|
270
|
+
|
|
271
|
+
## Safety First
|
|
272
|
+
|
|
273
|
+
* **Verify critical submissions**: `canvas-cli` verifies submissions automatically, but for high-stakes work (finals, midterms) you should still check the Canvas web UI after uploading.
|
|
274
|
+
* **Disclaimer**: This is an independent, personal project and is **not affiliated** with, authorized, or endorsed by Instructure, the Canvas LMS, or any university. Use at your own risk.
|
|
275
|
+
* **Academic integrity**: Make sure your use of automation tools complies with your university's acceptable use policy and academic integrity guidelines.
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# canvas-cli
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Linux-Viking/canvas-cli/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
A lightning-fast, terminal-based operating system for your degree.
|
|
6
|
+
|
|
7
|
+
`canvas-cli` is a command-line interface for the Canvas Learning Management System (LMS). It lets students check grades, view upcoming assignments, take part in discussion boards, bulk-download course files, and submit assignments (PDFs, documents, code) from the terminal without opening a web browser.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
* **Submissions**: Upload local files directly to assignments using Canvas's native 3-step upload protocol, with automatic post-submission verification.
|
|
12
|
+
* **To-Do List**: View upcoming assignments and due dates across all active courses.
|
|
13
|
+
* **Grades**: Check your current score and letter grade for every course.
|
|
14
|
+
* **Discussion Boards**: Read prompts and replies, and post top-level or threaded replies.
|
|
15
|
+
* **Bulk File Downloader**: Download all slides, syllabi, and readings from a course with one command.
|
|
16
|
+
* **Inbox**: Read your unread Canvas messages.
|
|
17
|
+
* **Aliases**: Map Canvas IDs (like `123456`) to memorable names (like `cs101`).
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Requires **Python 3.11 or newer**.
|
|
22
|
+
|
|
23
|
+
### Recommended: pipx
|
|
24
|
+
|
|
25
|
+
[pipx](https://pipx.pypa.io/) installs the CLI into its own isolated environment and puts `canvas-cli` on your `PATH`.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pipx install git+https://github.com/Linux-Viking/canvas-cli.git
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Once it's published on PyPI, it will be:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pipx install canvas-term
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> The PyPI package is named **`canvas-term`** (`canvas-cli` is taken by an unrelated project), but the command it installs is still **`canvas-cli`**.
|
|
38
|
+
|
|
39
|
+
### pip
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
python3 -m pip install --user git+https://github.com/Linux-Viking/canvas-cli.git
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Upgrading and uninstalling
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pipx upgrade canvas-term
|
|
49
|
+
pipx uninstall canvas-term
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
### 1. Generate an API token
|
|
55
|
+
|
|
56
|
+
1. Log into your school's Canvas website.
|
|
57
|
+
2. Click **Account** (your profile picture) → **Settings**.
|
|
58
|
+
3. Scroll to **Approved Integrations** and click **+ New Access Token**.
|
|
59
|
+
4. Give it a purpose (e.g. `canvas-cli`), optionally an expiry date, and click **Generate Token**.
|
|
60
|
+
5. Copy the token immediately. Canvas won't show it again.
|
|
61
|
+
|
|
62
|
+
### 2. Configure the CLI
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
canvas-cli config
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You'll be prompted for:
|
|
69
|
+
|
|
70
|
+
* **Canvas Domain**: your school's Canvas URL, e.g. `https://school.instructure.com`. Must be `https://`; a bare hostname is fine.
|
|
71
|
+
* **Canvas API Token**: paste the token. Input is hidden.
|
|
72
|
+
|
|
73
|
+
The CLI then checks the token by asking Canvas who you are:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
Configuration saved for https://school.instructure.com.
|
|
77
|
+
Verifying token...
|
|
78
|
+
Logged in as Ada Lovelace.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Re-run `canvas-cli config` whenever your token expires. Your aliases are kept.
|
|
82
|
+
|
|
83
|
+
#### Non-interactive setup
|
|
84
|
+
|
|
85
|
+
The token is deliberately **not** accepted as a command-line argument, because arguments end up in shell history and process listings. For scripts, pipe it on stdin:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pass show canvas/token | canvas-cli config --url https://school.instructure.com --token-stdin
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Using an environment variable instead of the keyring
|
|
92
|
+
|
|
93
|
+
If `CANVAS_TOKEN` is set, it takes priority over the keyring. This is useful on servers, in containers, or where no keyring is available:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
export CANVAS_TOKEN="$(pass show canvas/token)"
|
|
97
|
+
canvas-cli grades
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Where things are stored
|
|
101
|
+
|
|
102
|
+
| What | Where |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| API token | Your OS keyring (macOS Keychain, Windows Credential Locker, or Linux Secret Service such as GNOME Keyring or KWallet), or `$CANVAS_TOKEN` |
|
|
105
|
+
| Canvas URL and aliases | `~/.canvas_cli.json` (permissions `0600`, never contains the token) |
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
Every command and group accepts `-h`, `--help`, or a trailing `help`:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
canvas-cli help
|
|
113
|
+
canvas-cli course help
|
|
114
|
+
canvas-cli submit -h
|
|
115
|
+
canvas-cli --version
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Courses, modules, and items
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
canvas-cli list # active courses and their IDs
|
|
122
|
+
canvas-cli course 123456 list # modules in a course
|
|
123
|
+
canvas-cli course 123456 module 7890 list # items in a module
|
|
124
|
+
canvas-cli course 123456 module 7890 item 555 details # item info + assignment description
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Aliases
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
canvas-cli alias set cs101 123456
|
|
131
|
+
canvas-cli course cs101 list
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Aliases work anywhere a course, module, item, assignment, or topic ID is expected.
|
|
135
|
+
|
|
136
|
+
### Grades, to-dos, and inbox
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
canvas-cli grades
|
|
140
|
+
canvas-cli todo
|
|
141
|
+
canvas-cli inbox list
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Submitting an assignment
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
canvas-cli submit ./my_essay.pdf cs101 987654
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
You'll see a pre-submission summary and must confirm. After uploading, the CLI asks Canvas to confirm that the submission was received and the file is attached.
|
|
151
|
+
|
|
152
|
+
> **Find the assignment ID** with `canvas-cli course <course> module <module> item <item> details`, which prints the exact `submit` command to run.
|
|
153
|
+
|
|
154
|
+
### Discussions
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# List topics, then read a topic and its replies
|
|
158
|
+
canvas-cli course cs101 discuss list
|
|
159
|
+
canvas-cli course cs101 discuss view 555123
|
|
160
|
+
|
|
161
|
+
# Read the threaded replies under one entry
|
|
162
|
+
canvas-cli course cs101 discuss view 555123 --entry-id 999888
|
|
163
|
+
|
|
164
|
+
# Reply to the main prompt (\n becomes a line break)
|
|
165
|
+
canvas-cli course cs101 discuss reply 555123 "Here is my response...\nSecond paragraph."
|
|
166
|
+
|
|
167
|
+
# Reply from a file (newlines are preserved)
|
|
168
|
+
canvas-cli course cs101 discuss reply 555123 --file ./response.md
|
|
169
|
+
|
|
170
|
+
# Threaded reply to a specific student
|
|
171
|
+
canvas-cli course cs101 discuss reply 555123 "I agree!" --entry-id 999888
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Downloading course files
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
canvas-cli course cs101 files download # saves to ./course_<id>_files/
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Errors and troubleshooting
|
|
181
|
+
|
|
182
|
+
Commands exit with status `0` on success and non-zero on failure, so you can use them in scripts.
|
|
183
|
+
|
|
184
|
+
| Message | What to do |
|
|
185
|
+
| --- | --- |
|
|
186
|
+
| `No API token configured` | Run `canvas-cli config`. |
|
|
187
|
+
| `Canvas rejected your API token (401 Unauthorized)…` | Your token expired or was revoked. Generate a new one and run `canvas-cli config`. |
|
|
188
|
+
| `Canvas is rate limiting requests…` | The CLI already retried with backoff. Wait a minute and try again. |
|
|
189
|
+
| `Could not connect to …` / `… timed out` | Check your network connection and Canvas URL. Read-only requests are retried automatically. Submissions and replies are **never** retried automatically, so they can't be posted twice. |
|
|
190
|
+
| `Permission denied (403)` | Your account doesn't have access to that resource (e.g. the course is concluded or the item is locked). |
|
|
191
|
+
| `Not found (404)` | Check the ID or alias. In `module list`, use the ID shown in the first column. |
|
|
192
|
+
| `Canvas URL must use https://` | Re-run `canvas-cli config` with an `https://` URL. |
|
|
193
|
+
|
|
194
|
+
### Keyring troubleshooting (Linux)
|
|
195
|
+
|
|
196
|
+
`canvas-cli` uses the [`keyring`](https://pypi.org/project/keyring/) library. On a desktop with GNOME Keyring or KWallet running, it works out of the box. On headless servers, WSL, or minimal installs, there may be no keyring service:
|
|
197
|
+
|
|
198
|
+
* **`Could not read/save the API token to the system keyring`**: either start a Secret Service provider (e.g. `gnome-keyring-daemon`) or use the `CANVAS_TOKEN` environment variable.
|
|
199
|
+
* **Warning about a plain-text keyring backend**: some setups fall back to `keyrings.alt`, which stores secrets unencrypted on disk. `canvas-cli config` warns you if so. Prefer a real keyring or `CANVAS_TOKEN`.
|
|
200
|
+
* Run `pipx run keyring --list-backends` to see which keyring backends are available.
|
|
201
|
+
|
|
202
|
+
## Security
|
|
203
|
+
|
|
204
|
+
* Your API token is stored only in the OS keyring (or read from `$CANVAS_TOKEN`). It is never written to the config file, accepted as a command-line argument, or printed in output. Error messages are redacted.
|
|
205
|
+
* The token is sent only over `https://`, and only to your configured Canvas host. File downloads and uploads to external storage (e.g. S3) never receive it.
|
|
206
|
+
* Treat your token like a password: it grants full access to your Canvas account. Set an expiry date when you generate it and revoke it in Canvas settings if it's ever exposed.
|
|
207
|
+
|
|
208
|
+
Found a security issue? Please open a private [security advisory](https://github.com/Linux-Viking/canvas-cli/security/advisories/new) rather than a public issue.
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
git clone https://github.com/Linux-Viking/canvas-cli.git
|
|
214
|
+
cd canvas-cli
|
|
215
|
+
python3 -m venv .venv
|
|
216
|
+
source .venv/bin/activate
|
|
217
|
+
pip install --editable ".[dev]"
|
|
218
|
+
|
|
219
|
+
pytest # run the test suite (no network or real keyring needed)
|
|
220
|
+
ruff check . # lint
|
|
221
|
+
black . && isort . # format
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
CI runs linting, tests on Python 3.11–3.14 (plus macOS and Windows), a build and `pipx install` smoke test, and a [gitleaks](https://github.com/gitleaks/gitleaks) secret scan of the full git history.
|
|
225
|
+
|
|
226
|
+
### Releasing
|
|
227
|
+
|
|
228
|
+
Releases are published to PyPI by `.github/workflows/publish.yml` using [trusted publishing](https://docs.pypi.org/trusted-publishers/), so no PyPI API token is stored anywhere.
|
|
229
|
+
|
|
230
|
+
1. Bump `__version__` in `canvas_cli/__init__.py`.
|
|
231
|
+
2. Create a GitHub release tagged `v<version>` (e.g. `v0.2.0`).
|
|
232
|
+
|
|
233
|
+
## Safety First
|
|
234
|
+
|
|
235
|
+
* **Verify critical submissions**: `canvas-cli` verifies submissions automatically, but for high-stakes work (finals, midterms) you should still check the Canvas web UI after uploading.
|
|
236
|
+
* **Disclaimer**: This is an independent, personal project and is **not affiliated** with, authorized, or endorsed by Instructure, the Canvas LMS, or any university. Use at your own risk.
|
|
237
|
+
* **Academic integrity**: Make sure your use of automation tools complies with your university's acceptable use policy and academic integrity guidelines.
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
[MIT](LICENSE)
|