cass.apis¶
Typed Canvas LMS client and response schemas (msgspec.Struct types, Canvas-prefixed).
cass.apis ¶
External service API clients and response schemas.
canvas ¶
Canvas LMS integration — API client, roster matching, eGrades export.
auth ¶
Canvas authentication — API token or browser session cookie.
Two ways to authenticate against the Canvas API:
TokenAuth: a personal API token sent as a Bearer header. Read from.canvastokenor$CANVAS_TOKEN.SessionAuth: thecanvas_sessionand_csrf_tokencookies copied from a logged-in browser. Read from.canvascreds. Useful when no API token is available; cookies expire after roughly a day.
find_auth picks whichever is configured, preferring .canvastoken
because a token lasts months while browser cookies last about a day.
CanvasAuthError ¶
Bases: RuntimeError
Canvas rejected our credentials, with instructions on how to fix them.
Browser ¶
Bases: StrEnum
Supported browser imports on macOS.
BrowserSource
dataclass
¶
Browser profile and Canvas origin authorized to refresh a credential file.
TokenAuth
dataclass
¶
Bearer-token authentication.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
Canvas personal API token. |
required |
source
|
str
|
Where the token came from (file name or |
required |
SessionAuth
dataclass
¶
SessionAuth(
session: str,
csrf_token: str,
source: str,
browser_source: BrowserSource | None = None,
)
Browser session-cookie authentication.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
str
|
Value of the |
required |
csrf_token
|
str
|
URL-decoded value of the |
required |
source
|
str
|
File the cookies were read from. |
required |
browser_source
|
BrowserSource | None
|
Browser and profile to refresh an imported session from. |
None
|
parse_creds ¶
Parse a .canvascreds file of name=value cookie lines.
Values may be quoted (as copied from browser devtools) and the CSRF token may be URL-encoded or decoded; both forms are normalised.
Raises:
| Type | Description |
|---|---|
SystemExit
|
If |
find_auth ¶
Locate Canvas credentials for the project at root.
Order: .canvastoken, .canvascreds (session cookie), $CANVAS_TOKEN.
Returns:
| Type | Description |
|---|---|
CanvasAuth | None
|
The configured auth, or |
check_request ¶
Fail fast before sending a request the credentials cannot satisfy.
Raises:
| Type | Description |
|---|---|
CanvasAuthError
|
For a write with a session cookie but no CSRF token. |
check_response ¶
Translate credential failures into a CanvasAuthError with guidance.
Raises:
| Type | Description |
|---|---|
CanvasAuthError
|
On 401, or on a CSRF-rejected write under session auth. |
browser ¶
Import a Canvas session from Brave or Google Chrome on macOS.
read_browser_session ¶
Read Canvas cookies from one profile, using macOS Keychain access.
validate_session ¶
validate_session(
auth: SessionAuth,
origin: str,
*,
transport: BaseTransport | None = None,
) -> None
Check authentication with a read-only request before replacing credentials.
save_browser_session ¶
Atomically replace the credential file with owner-only permissions.
login_from_browser ¶
login_from_browser(
root: Path,
base_url: str,
profile: str = "Default",
*,
browser: Browser = Browser.BRAVE,
transport: BaseTransport | None = None,
) -> SessionAuth
Import, validate, and save a refreshable browser session for this project.
client ¶
Canvas LMS API client — typed CRUD for every Canvas resource.
Provides CanvasClient, a typed httpx client with course_id baked in.
All methods return msgspec.Struct instances, never raw dicts. The client is
assembled from one mixin per resource; base holds the transport, auth
lookup, pagination, and the shared _resolve helper.
CanvasClient(..., dry_run=True) records writes instead of sending them;
read them from planned_requests and render with
cass.apis.canvas.dry_run.format_plan.
CanvasAPIError ¶
Bases: HTTPStatusError
A Canvas request failed with a 4xx/5xx status.
Attributes:
| Name | Type | Description |
|---|---|---|
method |
HTTP method of the failed request. |
|
path |
Request path without the |
|
status_code |
HTTP status code. |
|
canvas_message |
Canvas's own error message, or the start of the body. |
BaseClient ¶
BaseClient(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Typed Canvas LMS API client with course_id baked in.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_url
|
str | None
|
Canvas instance URL (e.g. |
None
|
token
|
str | None
|
Canvas API bearer token (shortcut for |
None
|
course_id
|
int | None
|
Canvas course ID for all requests. |
None
|
auth
|
CanvasAuth | None
|
Credentials to use; defaults to whatever |
None
|
transport
|
BaseTransport | None
|
HTTP transport override (tests inject a mock here). |
None
|
time_zone
|
str | None
|
IANA course time zone; defaults to |
None
|
dry_run
|
bool
|
Record writes instead of sending them (see
|
False
|
planned_requests
property
¶
Writes a dry run recorded, in order (empty when not a dry run).
Render them with format_plan.
time_zone
property
¶
IANA time zone of the course (from cass.toml, else fetched once).
from_config
classmethod
¶
Build a client for the course a cass.toml describes.
Reads the base URL, course ID and time zone from path, and
credentials (.canvastoken / .canvascreds) from its directory,
without changing the project config the CLI uses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
A cass.toml file, which may have any name. |
required |
**kwargs
|
Any
|
Passed to the constructor (e.g. |
{}
|
Raises:
| Type | Description |
|---|---|
SystemExit
|
If the file or its credentials are missing. |
get_all ¶
get_all(
path: str,
params: Mapping[str, object]
| Sequence[tuple[str, object]]
| None = None,
) -> list[dict[str, Any]]
GET every page of a Canvas list endpoint (Link header pagination).
params (and per_page=100, unless given) apply to the first
request only; each later page is requested from the next URL
Canvas returns, verbatim.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
API path in any form |
required |
params
|
Mapping[str, object] | Sequence[tuple[str, object]] | None
|
Query parameters as a mapping or a list of pairs (repeated
keys such as |
None
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
Items from list pages concatenated; a non-list page is appended |
list[dict[str, Any]]
|
as a single item. |
course_path ¶
Course-scoped API path.
For example, course_path('/quizzes') gives /courses/{id}/quizzes.
request ¶
Send any request with cass's auth and retry handling.
path may be /api/v1/x, /x or x; use course_path()
for course-relative paths. data may be a dict or a list of pairs
(repeated keys are kept); other kwargs go to httpx. Raises
CanvasAPIError on a 4xx/5xx response.
publish ¶
Publish a resource (module, assignment, or quiz).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource
|
str
|
Resource type ( |
required |
resource_id
|
int
|
Canvas resource ID. |
required |
unpublish ¶
Unpublish a resource (module, assignment, or quiz).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource
|
str
|
Resource type ( |
required |
resource_id
|
int
|
Canvas resource ID. |
required |
RetryTransport ¶
RetryTransport(
*,
auth: CanvasAuth,
retries: int = 0,
wrapped: BaseTransport | None = None,
refresh: Callable[[], SessionAuth] | None = None,
)
Bases: BaseTransport
Wraps a transport with 429 retry, backoff, throttling, and auth checks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
auth
|
CanvasAuth
|
Credentials in use; credential failures (401, CSRF rejection)
are raised as |
required |
retries
|
int
|
Connection-level retries for the underlying HTTP transport. |
0
|
wrapped
|
BaseTransport | None
|
Transport to delegate to (defaults to |
None
|
refresh
|
Callable[[], SessionAuth] | None
|
Import fresh credentials after a 401, at most once per request. |
None
|
CanvasClient ¶
CanvasClient(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: CourseMixin, ModulesMixin, PagesMixin, AssignmentsMixin, GradesMixin, QuizzesMixin, FilesMixin, AnnouncementsMixin, CalendarMixin, TabsMixin, BaseClient
Typed Canvas LMS API client with course_id baked in.
See BaseClient for constructor arguments.
get_auth ¶
Locate Canvas credentials for the current project.
Prefers .canvastoken, then .canvascreds (browser session cookie),
then $CANVAS_TOKEN.
Raises:
| Type | Description |
|---|---|
SystemExit
|
If no credentials are found. |
get_token ¶
Read the Canvas API token from .canvastoken or $CANVAS_TOKEN.
Raises:
| Type | Description |
|---|---|
SystemExit
|
If no token is found. |
resource_key ¶
Map a plural resource name to Canvas API parameter key.
announcements ¶
Announcements (discussion topics flagged as announcements).
AnnouncementsMixin ¶
AnnouncementsMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Announcements (discussion topics flagged as announcements).
List course announcements.
Returns:
| Type | Description |
|---|---|
list[CanvasAnnouncement]
|
Announcements sorted by posted_at descending. |
Resolve an announcement by ID or case-insensitive title.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no announcement matches, or the title is ambiguous. |
Create an announcement.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
str
|
Announcement title. |
required |
message
|
str
|
HTML body. |
required |
Returns:
| Type | Description |
|---|---|
CanvasAnnouncement
|
The created announcement. |
Update an announcement.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
topic_id
|
int
|
Discussion topic ID. |
required |
**kwargs
|
object
|
Fields to update (title, message). |
{}
|
Returns:
| Type | Description |
|---|---|
CanvasAnnouncement
|
The updated announcement. |
assignments ¶
Assignments and assignment groups.
AssignmentsMixin ¶
AssignmentsMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Assignments and assignment groups.
List all course assignments.
Returns:
| Type | Description |
|---|---|
list[CanvasAssignmentResponse]
|
Assignments from all assignment groups. |
Get a single assignment by ID.
create_assignment(
name: str,
*,
points_possible: float = 0.0,
due_at: str | None = None,
submission_types: list[str] | None = None,
published: bool = False,
assignment_group_id: int | None = None,
description: str | None = None,
grading_type: str = "points",
) -> CanvasAssignmentResponse
Create a new assignment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Assignment name. |
required |
points_possible
|
float
|
Total points. |
0.0
|
due_at
|
str | None
|
Due date in ISO 8601 format. |
None
|
submission_types
|
list[str] | None
|
Allowed submission types. |
None
|
published
|
bool
|
Whether to publish immediately. |
False
|
assignment_group_id
|
int | None
|
Assignment group to place in. |
None
|
description
|
str | None
|
HTML description. |
None
|
grading_type
|
str
|
Grading type (points, letter_grade, etc.). |
'points'
|
Returns:
| Type | Description |
|---|---|
CanvasAssignmentResponse
|
The created assignment. |
Update an assignment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assignment_id
|
int
|
Canvas assignment ID. |
required |
**kwargs
|
object
|
Fields to update (name, points_possible, due_at, published, etc.). |
{}
|
Returns:
| Type | Description |
|---|---|
CanvasAssignmentResponse
|
The updated assignment. |
List assignment groups (grade categories).
Returns:
| Type | Description |
|---|---|
list[CanvasAssignmentGroup]
|
Assignment groups with weights and rules. |
create_assignment_group(
name: str,
*,
position: int | None = None,
group_weight: float | None = None,
) -> CanvasAssignmentGroup
Create a new assignment group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Group name. |
required |
position
|
int | None
|
Optional position in the group list. |
None
|
group_weight
|
float | None
|
Optional percentage weight for weighted grades. |
None
|
Returns:
| Type | Description |
|---|---|
CanvasAssignmentGroup
|
The created assignment group. |
Delete an assignment group (Canvas also deletes its assignments).
Resolve an assignment group by numeric ID or name (case-insensitive).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no group matches; the message lists the available groups. |
Resolve an assignment by numeric ID or name (case-insensitive).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no assignment matches. |
base ¶
Canvas client foundation — auth lookup, HTTP transport, and BaseClient.
Resource mixins in this package subclass BaseClient and are combined into
CanvasClient in __init__.
RetryTransport ¶
RetryTransport(
*,
auth: CanvasAuth,
retries: int = 0,
wrapped: BaseTransport | None = None,
refresh: Callable[[], SessionAuth] | None = None,
)
Bases: BaseTransport
Wraps a transport with 429 retry, backoff, throttling, and auth checks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
auth
|
CanvasAuth
|
Credentials in use; credential failures (401, CSRF rejection)
are raised as |
required |
retries
|
int
|
Connection-level retries for the underlying HTTP transport. |
0
|
wrapped
|
BaseTransport | None
|
Transport to delegate to (defaults to |
None
|
refresh
|
Callable[[], SessionAuth] | None
|
Import fresh credentials after a 401, at most once per request. |
None
|
BaseClient ¶
BaseClient(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Typed Canvas LMS API client with course_id baked in.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_url
|
str | None
|
Canvas instance URL (e.g. |
None
|
token
|
str | None
|
Canvas API bearer token (shortcut for |
None
|
course_id
|
int | None
|
Canvas course ID for all requests. |
None
|
auth
|
CanvasAuth | None
|
Credentials to use; defaults to whatever |
None
|
transport
|
BaseTransport | None
|
HTTP transport override (tests inject a mock here). |
None
|
time_zone
|
str | None
|
IANA course time zone; defaults to |
None
|
dry_run
|
bool
|
Record writes instead of sending them (see
|
False
|
property
¶Writes a dry run recorded, in order (empty when not a dry run).
Render them with format_plan.
property
¶IANA time zone of the course (from cass.toml, else fetched once).
classmethod
¶Build a client for the course a cass.toml describes.
Reads the base URL, course ID and time zone from path, and
credentials (.canvastoken / .canvascreds) from its directory,
without changing the project config the CLI uses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
A cass.toml file, which may have any name. |
required |
**kwargs
|
Any
|
Passed to the constructor (e.g. |
{}
|
Raises:
| Type | Description |
|---|---|
SystemExit
|
If the file or its credentials are missing. |
get_all(
path: str,
params: Mapping[str, object]
| Sequence[tuple[str, object]]
| None = None,
) -> list[dict[str, Any]]
GET every page of a Canvas list endpoint (Link header pagination).
params (and per_page=100, unless given) apply to the first
request only; each later page is requested from the next URL
Canvas returns, verbatim.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
API path in any form |
required |
params
|
Mapping[str, object] | Sequence[tuple[str, object]] | None
|
Query parameters as a mapping or a list of pairs (repeated
keys such as |
None
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
Items from list pages concatenated; a non-list page is appended |
list[dict[str, Any]]
|
as a single item. |
Course-scoped API path.
For example, course_path('/quizzes') gives /courses/{id}/quizzes.
Send any request with cass's auth and retry handling.
path may be /api/v1/x, /x or x; use course_path()
for course-relative paths. data may be a dict or a list of pairs
(repeated keys are kept); other kwargs go to httpx. Raises
CanvasAPIError on a 4xx/5xx response.
Publish a resource (module, assignment, or quiz).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource
|
str
|
Resource type ( |
required |
resource_id
|
int
|
Canvas resource ID. |
required |
Unpublish a resource (module, assignment, or quiz).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource
|
str
|
Resource type ( |
required |
resource_id
|
int
|
Canvas resource ID. |
required |
get_auth ¶
Locate Canvas credentials for the current project.
Prefers .canvastoken, then .canvascreds (browser session cookie),
then $CANVAS_TOKEN.
Raises:
| Type | Description |
|---|---|
SystemExit
|
If no credentials are found. |
get_token ¶
Read the Canvas API token from .canvastoken or $CANVAS_TOKEN.
Raises:
| Type | Description |
|---|---|
SystemExit
|
If no token is found. |
resource_key ¶
Map a plural resource name to Canvas API parameter key.
calendar ¶
Course calendar events.
CalendarMixin ¶
CalendarMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Course calendar events.
list_calendar_events(
*,
start_date: str | None = None,
end_date: str | None = None,
) -> list[CanvasCalendarEvent]
List calendar events on this course's calendar.
Canvas defaults to today's events only, so without a date range this requests every event on the course calendar.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
str | None
|
Inclusive lower bound (YYYY-MM-DD or ISO 8601). |
None
|
end_date
|
str | None
|
Inclusive upper bound (YYYY-MM-DD or ISO 8601). |
None
|
Returns:
| Type | Description |
|---|---|
list[CanvasCalendarEvent]
|
Calendar events (assignment due dates are not included). |
create_calendar_event(
title: str,
*,
start_at: str,
end_at: str | None = None,
description: str | None = None,
location_name: str | None = None,
all_day: bool = False,
) -> CanvasCalendarEvent
Create a calendar event on this course's calendar.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
str
|
Event title. |
required |
start_at
|
str
|
Start date/time (ISO 8601). |
required |
end_at
|
str | None
|
End date/time (ISO 8601). |
None
|
description
|
str | None
|
HTML description. |
None
|
location_name
|
str | None
|
Location name. |
None
|
all_day
|
bool
|
Ignore times and span the whole day. |
False
|
Returns:
| Type | Description |
|---|---|
CanvasCalendarEvent
|
The created event. |
Update a calendar event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_id
|
int
|
Calendar event ID. |
required |
**kwargs
|
object
|
Fields to update (title, start_at, end_at, description, location_name, all_day). |
{}
|
Returns:
| Type | Description |
|---|---|
CanvasCalendarEvent
|
The updated event. |
course ¶
Course, people, sections, enrollments, and grading standards.
CourseMixin ¶
CourseMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Course, people, sections, enrollments, and grading standards.
list_users(
enrollment_type: str | None = None,
*,
states: Sequence[str] = (),
) -> list[CanvasUser]
List course users with enrollments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enrollment_type
|
str | None
|
Filter by role (e.g. |
None
|
states
|
Sequence[str]
|
Enrollment states to include (e.g. |
()
|
Returns:
| Type | Description |
|---|---|
list[CanvasUser]
|
Users sorted by name. |
List students enrolled in the course.
Returns:
| Type | Description |
|---|---|
list[CanvasStudentResponse]
|
Students sorted by Canvas enrollment order. |
List all course sections.
Returns:
| Type | Description |
|---|---|
list[CanvasSection]
|
Sections with SIS IDs (if available). |
list_enrollments(
*,
enrollment_type: str | None = "StudentEnrollment",
states: Sequence[str] = ("active",),
include_scores: bool = True,
) -> list[CanvasEnrollment]
List enrollments, optionally with computed scores.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enrollment_type
|
str | None
|
Filter by type (default: StudentEnrollment);
|
'StudentEnrollment'
|
states
|
Sequence[str]
|
Enrollment states to include (default: active). |
('active',)
|
include_scores
|
bool
|
Include computed scores ( |
True
|
Returns:
| Type | Description |
|---|---|
list[CanvasEnrollment]
|
Enrollments, including computed_final_score when requested. |
List grading standards available for this course.
Returns:
| Type | Description |
|---|---|
list[CanvasGradingStandard]
|
Grading standards with scheme entries. |
files ¶
Files and folders.
FilesMixin ¶
FilesMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Files and folders.
List files in the course or a specific folder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
folder_id
|
int | None
|
Optional folder ID to scope the listing. |
None
|
Returns:
| Type | Description |
|---|---|
list[CanvasFile]
|
File metadata sorted by name. |
Resolve a file by ID or case-insensitive display name.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no file matches, or the name is ambiguous. |
List all folders in the course.
Returns:
| Type | Description |
|---|---|
list[CanvasFolder]
|
Folders with hierarchy info. |
Find a folder by path relative to the course files root.
Matching is case-insensitive.
Returns:
| Type | Description |
|---|---|
CanvasFolder | None
|
The folder, or |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the path starts with the root folder's name. |
Resolve a folder by exact ID, else by path.
Raises:
| Type | Description |
|---|---|
CanvasNotFoundError
|
If nothing matches. |
Create a folder by path, creating missing parents by default.
Existing folders are returned unchanged. "" returns the root folder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Folder path relative to the course files root. |
required |
parents
|
bool
|
Create missing intermediate folders. When |
True
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the path starts with the root folder's name, or
|
Delete a folder; force also deletes a non-empty folder.
update_file(
file_id: int,
*,
name: str | None = None,
folder_id: int | None = None,
locked: bool | None = None,
on_duplicate: Literal["rename", "overwrite"]
| None = None,
) -> CanvasFile
Rename, move or lock a file; only the given fields are sent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_id
|
int
|
Canvas file ID. |
required |
name
|
str | None
|
New display name. |
None
|
folder_id
|
int | None
|
ID of the folder to move the file into. |
None
|
locked
|
bool | None
|
Lock ( |
None
|
on_duplicate
|
Literal['rename', 'overwrite'] | None
|
What to do if the destination already has a file with the same name. |
None
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no field is given. |
upload_file(
local_path: str,
*,
folder: str = "",
name: str | None = None,
on_duplicate: Literal[
"rename", "overwrite"
] = "overwrite",
locked: bool = False,
) -> CanvasFile
Upload a file to the course.
Uses Canvas's 3-step file upload flow: 1. Notify Canvas to get an upload URL 2. POST the file to the upload URL 3. Confirm the upload
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
local_path
|
str
|
Path to the local file. |
required |
folder
|
str
|
Destination folder path relative to the course files root
(e.g. |
''
|
name
|
str | None
|
Name in Canvas; defaults to the local file name. |
None
|
on_duplicate
|
Literal['rename', 'overwrite']
|
|
'overwrite'
|
locked
|
bool
|
Lock the file after uploading. |
False
|
Returns:
| Type | Description |
|---|---|
CanvasFile
|
The uploaded file metadata. |
normalize_folder_path ¶
Strip whitespace and slashes and drop empty segments.
Example: "/a//b/" becomes "a/b"; "" stays "".
folder_paths ¶
Map each folder ID to its path relative to the course files root.
The root folder (the one without a parent) maps to "". Canvas names the
root course files; that prefix is removed from every path.
grades ¶
Submissions, grade pushes, progress polling, and grade posting.
GradesMixin ¶
GradesMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Submissions, grade pushes, progress polling, and grade posting.
list_submissions(
assignment_id: int, *, include_user: bool = False
) -> list[CanvasSubmissionResponse]
List submissions for an assignment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assignment_id
|
int
|
Canvas assignment ID. |
required |
include_user
|
bool
|
Embed the submitting user in each submission. |
False
|
Returns:
| Type | Description |
|---|---|
list[CanvasSubmissionResponse]
|
All submissions for the assignment. |
list_student_submissions(
student_ids: Sequence[int],
*,
assignment_ids: Sequence[int] = (),
) -> list[CanvasSubmissionResponse]
List submissions for students across assignments.
Student IDs are sent in chunks of 100 (one request per chunk).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
student_ids
|
Sequence[int]
|
Canvas user IDs. |
required |
assignment_ids
|
Sequence[int]
|
Restrict to these assignments; empty means all. |
()
|
Returns:
| Type | Description |
|---|---|
list[CanvasSubmissionResponse]
|
Submissions for all chunks, concatenated. Empty when no students. |
update_submission(
assignment_id: int,
user_id: int,
*,
excuse: bool | None = None,
late_policy_status: str | None = None,
) -> CanvasSubmissionResponse
Update excused or late-policy status on one submission.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assignment_id
|
int
|
Canvas assignment ID. |
required |
user_id
|
int
|
Student's Canvas user ID. |
required |
excuse
|
bool | None
|
Excuse (True) or un-excuse (False) the submission. Either way Canvas clears the grade and score. |
None
|
late_policy_status
|
str | None
|
Late policy status (e.g. |
None
|
Returns:
| Type | Description |
|---|---|
CanvasSubmissionResponse
|
The updated submission. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If neither field is given. |
Push a single grade to Canvas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assignment_id
|
int
|
Canvas assignment ID. |
required |
student_canvas_id
|
int
|
Student's Canvas user ID. |
required |
grade
|
str
|
Grade string to post. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True on success, False on failure. |
Push grades in bulk for one assignment via the update_grades endpoint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assignment_id
|
int
|
Canvas assignment ID. |
required |
grade_data
|
dict[int, str]
|
Mapping of student_canvas_id → posted_grade string. |
required |
Returns:
| Type | Description |
|---|---|
CanvasProgress
|
Progress object for tracking completion. |
Check the status of an async Canvas operation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
progress_id
|
int
|
Progress object ID. |
required |
Returns:
| Type | Description |
|---|---|
CanvasProgress
|
Current progress state. |
Poll a progress object until completion or timeout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
progress_id
|
int
|
Progress object ID. |
required |
timeout
|
float
|
Maximum seconds to wait. |
120.0
|
Returns:
| Type | Description |
|---|---|
CanvasProgress
|
Completed or failed progress object. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the progress times out or fails. |
Post (reveal) grades to students for a manual-post assignment.
Uses the Canvas GraphQL postAssignmentGrades mutation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assignment_id
|
int
|
Canvas assignment ID. |
required |
graded_only
|
bool
|
If True, only post grades for graded submissions. |
True
|
Returns:
| Type | Description |
|---|---|
CanvasProgress | None
|
Progress object for tracking, or None if no progress was started. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the mutation returns validation errors. |
Hide grades from students for a manual-post assignment.
Uses the Canvas GraphQL hideAssignmentGrades mutation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
assignment_id
|
int
|
Canvas assignment ID. |
required |
Returns:
| Type | Description |
|---|---|
CanvasProgress | None
|
Progress object for tracking, or None if no progress was started. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the mutation returns validation errors. |
modules ¶
Modules and module items.
ModulesMixin ¶
ModulesMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Modules and module items.
List items in a module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_id
|
int
|
Canvas module ID. |
required |
Returns:
| Type | Description |
|---|---|
list[CanvasModuleItem]
|
Module items sorted by position. |
Create a new module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Module name. |
required |
position
|
int | None
|
Optional position in the module list. |
None
|
Returns:
| Type | Description |
|---|---|
CanvasModule
|
The created module. |
Update a module.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_id
|
int
|
Canvas module ID. |
required |
**kwargs
|
object
|
Fields to update (name, position, published). |
{}
|
Returns:
| Type | Description |
|---|---|
CanvasModule
|
The updated module. |
create_module_item(
module_id: int,
*,
item_type: str,
content_id: int | None = None,
title: str | None = None,
indent: int | None = None,
page_url: str | None = None,
external_url: str | None = None,
) -> CanvasModuleItem
Add an item to a module.
Only the fields given are sent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_id
|
int
|
Canvas module ID. |
required |
item_type
|
str
|
Item type (Assignment, Quiz, File, Page, SubHeader, ExternalUrl, etc.). |
required |
content_id
|
int | None
|
ID of the linked content (Assignment, Quiz, File). |
None
|
title
|
str | None
|
Item title; Canvas uses the content's name when omitted. |
None
|
indent
|
int | None
|
Indent level. |
None
|
page_url
|
str | None
|
Slug of the linked wiki page (Page items). |
None
|
external_url
|
str | None
|
Target URL (ExternalUrl items). |
None
|
Returns:
| Type | Description |
|---|---|
CanvasModuleItem
|
The created module item. |
update_module_item(
module_id: int,
item_id: int,
*,
title: str | None = None,
indent: int | None = None,
position: int | None = None,
published: bool | None = None,
current: CanvasModuleItem | None = None,
) -> CanvasModuleItem
Update a module item; only the fields given are sent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
module_id
|
int
|
Canvas module ID. |
required |
item_id
|
int
|
Module item ID. |
required |
title
|
str | None
|
New title. |
None
|
indent
|
int | None
|
New indent level. |
None
|
position
|
int | None
|
New position within the module. |
None
|
published
|
bool | None
|
New published state. |
None
|
current
|
CanvasModuleItem | None
|
The item as it is now. |
None
|
Returns:
| Type | Description |
|---|---|
CanvasModuleItem
|
The updated item. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no field is given. |
Remove an item from a module (the linked content is untouched).
Resolve a module item by ID or title (case-insensitive).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no item matches or several share the title. |
Resolve a module by numeric ID or name (case-insensitive).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no module matches. |
pages ¶
Course wiki pages.
PagesMixin ¶
PagesMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Course wiki pages.
List the course's wiki pages.
Returns:
| Type | Description |
|---|---|
list[CanvasPage]
|
Pages with their URL slugs and published state. |
quizzes ¶
Classic quizzes, quiz questions, reports, and quiz submissions.
QuizzesMixin ¶
QuizzesMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Classic quizzes and quiz questions.
Create a quiz with its questions.
Fills unset settings from QUIZ_CREATE_DEFAULTS, posts the quiz
unpublished, creates the declared question groups, posts each question
in file order (into its group), orders groups and entries when there
are groups, then re-saves the quiz (applying spec.published) so
Canvas recomputes
question_count and points_possible. If a question post fails
the partial quiz is deleted and the error re-raised.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
QuizSpec
|
Settings and questions; times are parsed in the course zone. |
required |
assignment_group_id
|
int | None
|
Assignment group to place the quiz in. |
None
|
Returns:
| Type | Description |
|---|---|
CanvasQuiz
|
The quiz as re-fetched after the re-save. |
Update quiz settings.
Only the given Canvas fields are sent; questions are never touched.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
changes
|
dict[str, object]
|
Canvas field name → new value (see |
required |
Returns:
| Type | Description |
|---|---|
CanvasQuiz
|
The updated quiz. |
List a quiz's questions in the order the questions API returns them.
That order follows Canvas's stored positions, but each question's
position field is null for API-created questions; see
canvas_layout for rebuilding the quiz order.
include[]=plain_html returns the HTML as stored. Without it, Canvas
wraps each question's text in the account's theme CSS and JS and
rewrites file links, so the text would never match what was sent.
Concluded courses return 403 from the questions endpoint; then the
questions are rebuilt from /statistics, which carries text and
which answers are correct but no answer weights or names.
Returns:
| Type | Description |
|---|---|
tuple[list[CanvasQuizQuestion], bool]
|
|
create_quiz_question(
quiz_id: int,
question: QuestionSpec,
position: int,
*,
quiz_type: str = "assignment",
quiz_group_id: int | None = None,
) -> CanvasQuizQuestion
Add one question to a quiz.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
question
|
QuestionSpec
|
Question spec; |
required |
position
|
int
|
1-based position. |
required |
quiz_type
|
str
|
Decides the default points (0 for surveys, else 1). |
'assignment'
|
quiz_group_id
|
int | None
|
Question group to put the question in. |
None
|
Returns:
| Type | Description |
|---|---|
CanvasQuizQuestion
|
The created question. |
update_quiz_question(
quiz_id: int,
question_id: int,
fields: dict[str, object],
) -> CanvasQuizQuestion
Update one question (one call).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
question_id
|
int
|
Canvas question ID. |
required |
fields
|
dict[str, object]
|
Canvas question field → new value, e.g. |
required |
Returns:
| Type | Description |
|---|---|
CanvasQuizQuestion
|
The updated question. |
Delete one question (one call).
Create a question group (one call).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
fields
|
dict[str, object]
|
Canvas group fields: |
required |
Returns:
| Type | Description |
|---|---|
CanvasQuizGroup
|
The created group. |
Update a question group (one call); same fields as the create.
Delete a question group (one call).
Get one question group (one call).
Canvas has no endpoint that lists a quiz's groups.
Set the quiz's top-level order (one call).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
items
|
list[tuple[str, int]]
|
|
required |
Set the order of the questions inside a group (one call).
Re-save a quiz without notifying students (one call).
Classic quizzes recount questions and points only after a re-save.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
published
|
bool | None
|
Also set the published state when given. |
None
|
Ask Canvas to generate a student analysis report.
Canvas returns the existing report when one is already current, so repeating the call is cheap. Works on concluded courses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
all_versions
|
bool
|
Report every attempt instead of only the latest. |
False
|
Returns:
| Type | Description |
|---|---|
CanvasQuizReport
|
The report; |
Get a quiz report with its file and progress.
download_quiz_report(
quiz_id: int,
*,
all_versions: bool = False,
timeout: float = 300.0,
interval: float = 2.0,
) -> str
Generate a student analysis report, wait for it, and download it.
Generation typically takes about 30 seconds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quiz_id
|
int
|
Canvas quiz ID. |
required |
all_versions
|
bool
|
Report every attempt instead of only the latest. |
False
|
timeout
|
float
|
Maximum seconds to wait for Canvas to build the file. |
300.0
|
interval
|
float
|
Seconds between polls. |
2.0
|
Returns:
| Type | Description |
|---|---|
str
|
The report CSV text. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If generation fails or times out. |
List each student's latest attempt on a quiz.
Returns:
| Type | Description |
|---|---|
list[CanvasQuizSubmission]
|
One quiz submission per student who opened the quiz. |
Start a teacher preview attempt on a quiz.
Returns:
| Type | Description |
|---|---|
CanvasQuizSubmission
|
The preview's quiz submission. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
Canvas returned no quiz submission. |
List the questions of one quiz submission in the order it was drawn.
A quiz's ID from a numeric ID (no request) or a title.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no quiz has that title. |
Resolve a quiz by numeric ID or title (case-insensitive).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no quiz matches. |
tabs ¶
Course navigation tabs.
TabsMixin ¶
TabsMixin(
base_url: str | None = None,
token: str | None = None,
course_id: int | None = None,
*,
auth: CanvasAuth | None = None,
transport: BaseTransport | None = None,
time_zone: str | None = None,
dry_run: bool = False,
)
Bases: BaseClient
Course navigation tabs.
List course navigation tabs.
Returns:
| Type | Description |
|---|---|
list[CanvasTab]
|
Tabs with visibility and position. |
Show or hide a navigation tab.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tab_id
|
str
|
Tab ID string. |
required |
hidden
|
bool
|
True to hide, False to show. |
required |
Returns:
| Type | Description |
|---|---|
CanvasTab
|
The updated tab. |
Resolve a navigation tab by ID (e.g. syllabus) or label.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no tab matches. |
dry_run ¶
Dry run: record Canvas writes instead of sending them.
A dry-run client sends GETs as usual but records every other request and answers it with a synthetic 200 response, so chained calls (create a quiz, then add its questions) still work. New resources get placeholder IDs -1, -2, … and later requests to their paths are answered locally.
PlannedRequest
dataclass
¶
One write a dry run recorded instead of sending.
Attributes:
| Name | Type | Description |
|---|---|---|
method |
str
|
HTTP method. |
path |
str
|
Path relative to |
body |
dict[str, Any]
|
Parsed request body (form keys nested, as in |
DryRunRecorder ¶
Records planned writes and keeps the synthetic body of each written path.
stored ¶
Synthetic body for a path this dry run created or changed, if any.
has_placeholder ¶
Whether path contains a placeholder ID segment such as -1.
record ¶
record(
method: str,
path: str,
body: dict[str, Any],
fetch_current: Callable[[], dict[str, Any]],
) -> dict[str, Any]
Record a write and build its synthetic response body.
A POST to a collection creates a resource with the next placeholder
ID. Any other write merges the request fields into the resource's
current body: the stored one, else {} under a placeholder path,
else fetch_current() (called once per path). A /reorder POST
is recorded and answered with {}. Endpoints in _ENVELOPES
take and return their fields wrapped in a one-item list.
record_upload ¶
Record the file POST to an upload URL and build the file's body.
DryRunTransport ¶
Bases: BaseTransport
Sends GETs through wrapped; records everything else in recorder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
recorder
|
DryRunRecorder
|
Where planned writes and synthetic bodies are kept. |
required |
wrapped
|
BaseTransport
|
Transport for real GETs (cass's |
required |
api_root
|
str
|
The client's API base URL, e.g.
|
required |
format_plan ¶
Render planned writes, one line each.
A line is the method, the path with placeholder IDs shown as
<new N>, and the request fields as key=value pairs. Nested
values are shown as compact JSON and long values are cut to 60
characters.
egrades ¶
eGrades CSV export — UCSD final grade submission format.
Generates the 5-column CSV required by UCSD's eGrades system:
Last Name, First Name, Student ID, SectionId, Final_Assigned_Egrade
Uses the Canvas enrollments API for computed_final_score and the
course grading standard to convert percentages to letter grades.
score_to_letter ¶
Convert a percentage score to a letter grade using a grading scheme.
Canvas grading schemes are lists of {name, value} entries sorted
descending by value. Each entry means "scores >= value * 100 earn
this letter."
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pct
|
float | None
|
Percentage score (0-100), or None for missing. |
required |
scheme
|
list[CanvasGradingSchemeEntry]
|
Grading scheme entries (will be sorted internally). |
required |
Returns:
| Type | Description |
|---|---|
str
|
Letter grade string, or |
parse_sortable_name ¶
Parse Canvas sortable_name into (last_name, first_name).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sortable_name
|
str
|
Name in "Last, First" format. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Tuple of (last_name, first_name). Falls back to full string |
str
|
as last name if no comma found. |
generate_egrades ¶
Generate an eGrades CSV file from Canvas data.
Fetches enrollments with computed_final_score, resolves the active grading scheme, and writes the UCSD eGrades format CSV.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output
|
str | Path
|
Output file path. |
'egrades.csv'
|
Returns:
| Type | Description |
|---|---|
tuple[Path, int, list[str]]
|
Tuple of (path, row_count, warnings). |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no grading standard is configured or no students found. |
errors ¶
Canvas API errors — one exception type for every 4xx/5xx response.
CanvasNotFoundError ¶
Bases: RuntimeError
A name or ID matched nothing (as opposed to matching several).
CanvasAPIError ¶
Bases: HTTPStatusError
A Canvas request failed with a 4xx/5xx status.
Attributes:
| Name | Type | Description |
|---|---|---|
method |
HTTP method of the failed request. |
|
path |
Request path without the |
|
status_code |
HTTP status code. |
|
canvas_message |
Canvas's own error message, or the start of the body. |
raise_for_canvas_status ¶
Raise CanvasAPIError if response is a 4xx/5xx; otherwise do nothing.
matching ¶
Canvas LMS integration — roster fetching, submission retrieval, and grade push.
All raw API calls are delegated to CanvasClient in client.py.
get_token ¶
Read the Canvas API token from .canvastoken or $CANVAS_TOKEN.
Raises:
| Type | Description |
|---|---|
SystemExit
|
If no token is found. |
fetch_students ¶
Fetch all students enrolled in a Canvas course.
fetch_course_name ¶
Fetch the course name from the Canvas API.
fetch_course_time_zone ¶
Read the course's IANA time zone from Canvas.
fetch_students_with_sections ¶
fetch_students_with_sections(
course_id: int,
) -> tuple[list[CanvasStudentResponse], dict[int, str]]
Fetch students and build a canvas_id -> sis_section_id mapping.
Uses the users endpoint (with enrollments) and sections endpoint to resolve each student's SIS section ID.
Returns:
| Type | Description |
|---|---|
list[CanvasStudentResponse]
|
Tuple of (students, sis_section_map) where sis_section_map maps |
dict[int, str]
|
canvas_id to sis_section_id. |
fetch_canvas_assignments ¶
fetch_canvas_assignments(
course_id: int,
) -> tuple[list[CanvasAssignmentResponse], dict[int, str]]
Fetch all assignments and assignment group names from Canvas.
Returns:
| Type | Description |
|---|---|
list[CanvasAssignmentResponse]
|
Tuple of (assignments, group_names) where group_names maps |
dict[int, str]
|
assignment_group_id to group name. |
fetch_canvas_submissions ¶
fetch_canvas_submissions(
course_id: int,
canvas_assignment_id: int,
known_canvas_ids: set[int],
) -> list[CanvasSubmission]
Fetch submissions for a Canvas assignment, filtered to known students.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
course_id
|
int
|
Canvas course ID. |
required |
canvas_assignment_id
|
int
|
Canvas assignment ID. |
required |
known_canvas_ids
|
set[int]
|
Set of canvas_ids from the students table. |
required |
Returns:
| Type | Description |
|---|---|
list[CanvasSubmission]
|
CanvasSubmission domain objects for known students. |
push_grade ¶
Push a single grade to Canvas. Returns True on success, False on failure.
raw ¶
Helpers for raw Canvas API calls: path normalization and request bodies.
api_path ¶
Normalize a user-supplied API path to one relative to /api/v1.
An http(s):// URL is returned unchanged. Otherwise /api/v1/x,
/x and x all become /x.
form_content ¶
URL-encode key/value pairs as a form body, keeping repeated keys.
Values are encoded like httpx does: True/False become
true/false and None becomes an empty value.
parse_form ¶
Parse form pairs into nested data using the Rails bracket convention.
quiz[title] nests into {"quiz": {"title": ...}}, a[] collects
a list, and order[][id] builds a list of dicts. Keys without valid
brackets are kept as plain keys.
parse_body ¶
Read a request's JSON or form body as a dict ({} for anything else).
A JSON body that is not an object is returned as {"body": value}.
request_fields ¶
Remove a resource wrapper: {"quiz": {...}} becomes {...}.
parse_pairs ¶
Split KEY=VALUE strings at the first =, keeping order and repeats.
expand_course ¶
Replace every {course} in path with the course ID.
schema ¶
Canvas LMS API response types.
CanvasCourse ¶
Bases: Struct
Canvas course details.
CanvasStudentResponse ¶
Bases: Struct
Canvas student (user enrolled as student).
CanvasEnrollmentGrades ¶
Bases: Struct
Nested grades object inside a Canvas enrollment.
CanvasEnrollment ¶
CanvasUser ¶
Bases: Struct
Canvas user with optional enrollments.
CanvasSection ¶
Bases: Struct
Canvas course section.
CanvasGradingSchemeEntry ¶
Bases: Struct
Single entry in a Canvas grading scheme (e.g. A = 0.94).
CanvasGradingStandard ¶
Bases: Struct
Canvas grading standard with scheme entries.
CanvasModuleItem ¶
Bases: Struct
Single item within a Canvas module.
CanvasPage ¶
Bases: Struct
Canvas wiki page.
CanvasModule ¶
Bases: Struct
Canvas module (content grouping).
CanvasAssignmentResponse ¶
Bases: Struct
Canvas assignment.
CanvasAssignmentGroup ¶
Bases: Struct
Canvas assignment group (weighted grade category).
CanvasQuiz ¶
Bases: Struct
Canvas quiz.
CanvasQuizAnswer ¶
Bases: Struct
One answer on a Canvas quiz question.
CanvasQuizQuestion ¶
Bases: Struct
Canvas quiz question with its answers.
CanvasQuizGroup ¶
Bases: Struct
Canvas question group: draws pick_count of its questions per attempt.
CanvasQuizReportFile ¶
Bases: Struct
File attached to a generated quiz report.
CanvasQuizReport ¶
Bases: Struct
Canvas quiz report (include[]=file,progress).
file is None until Canvas finishes generating the CSV.
CanvasQuizSubmission ¶
Bases: Struct
A student's latest classic quiz attempt (/quizzes/:id/submissions).
CanvasFile ¶
Bases: Struct
Canvas file metadata.
CanvasFolder ¶
Bases: Struct
Canvas folder in the file hierarchy.
CanvasAnnouncement ¶
Bases: Struct
Canvas announcement (discussion_topic with is_announcement=true).
CanvasCalendarEvent ¶
Bases: Struct
Canvas calendar event (type=event; assignment due dates are not included).
CanvasTab ¶
Bases: Struct
Canvas course navigation tab.
CanvasSubmissionResponse ¶
Bases: Struct
Canvas submission API response.
CanvasProgress ¶
Bases: Struct
Canvas async operation progress tracker.
sync ¶
Canvas sync primitives — push grades and assignments to Canvas LMS.
Shared by both the CLI (cass gradebook push) and the NiceGUI viewer.
same_instant ¶
Compare two ISO timestamps by the moment they name, not their spelling.
Canvas returns UTC (...Z) while cass.toml may use a local offset.
Unparseable values fall back to plain string comparison.
values_equal ¶
Compare values loosely, handling datetime/string equivalence.
resolve_row_name ¶
Resolve a pending-change pk_key to a human-readable row name.
is_valid_grade ¶
Return True if grade is non-empty and not a placeholder.
build_grade_push_data ¶
Build {aid: {uid: grade}} from CanvasGrade list, filtering placeholders.
Returns:
| Type | Description |
|---|---|
tuple[dict[int, dict[int, str]], int]
|
Tuple of (grade_data_by_aid, skipped_count). |
get_post_manually_map ¶
Load {canvas_assignment_id: post_manually} from DB.
build_push_preview ¶
build_push_preview(
conn: Database,
grade_data_by_aid: dict[int, dict[int, str]],
grades: list[CanvasGrade],
) -> list[dict[str, object]]
Build a preview summary per assignment for push display.
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
List of dicts with |
push_grades ¶
push_grades(
client: CanvasClient,
conn: Database,
grade_data_by_aid: dict[int, dict[int, str]],
) -> list[dict[str, object]]
Bulk-push grades to Canvas, handling progress tracking and post_manually.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
CanvasClient
|
Authenticated Canvas API client. |
required |
conn
|
Database
|
SQLite database connection (for post_manually lookup). |
required |
grade_data_by_aid
|
dict[int, dict[int, str]]
|
|
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
List of result dicts with |
list[dict[str, object]]
|
and optionally |
resolve_group_ids ¶
Map assignment group names to IDs, case-insensitively.
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
|
list[str]
|
missing name is listed once, as first spelled. |
push_assignments ¶
push_assignments(
client: CanvasClient,
updates_by_id: dict[int, dict[str, object]],
) -> list[dict[str, object]]
Push assignment field updates to Canvas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
CanvasClient
|
Authenticated Canvas API client. |
required |
updates_by_id
|
dict[int, dict[str, object]]
|
|
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
List of result dicts with |
times ¶
Course-local time handling for Canvas timestamps.
Canvas stores instants in UTC. Users type times in the course's own zone.
parse_when turns a user string into an ISO 8601 instant with an offset;
format_when renders a Canvas instant in the course zone.
parse_when ¶
Parse a user-entered time into ISO 8601 with an offset.
Accepts YYYY-MM-DD, YYYY-MM-DD HH:MM, YYYY-MM-DDTHH:MM and
full ISO 8601. Naive values are localized to tz; a date alone means
midnight. Values that already carry an offset are returned unchanged.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the value cannot be parsed or tz is empty. |
check_when ¶
Fail early on a time parse_when would reject, without a time zone.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the value cannot be parsed. |
format_when ¶
Render an ISO instant in tz as YYYY-MM-DD HH:MM (or the date).
same_instant ¶
Compare two ISO timestamps by the moment they name, not their spelling.
Canvas returns UTC (...Z) while cass.toml may use a local offset.
Unparseable values fall back to plain string comparison.