Skip to content

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 .canvastoken or $CANVAS_TOKEN.
  • SessionAuth: the canvas_session and _csrf_token cookies 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
BrowserSource(
    profile: str,
    origin: str,
    path: Path,
    browser: Browser = Browser.BRAVE,
)

Browser profile and Canvas origin authorized to refresh a credential file.

TokenAuth dataclass
TokenAuth(token: str, source: str)

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 $CANVAS_TOKEN).

required
description property
description: str

Short human label for status output.

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 canvas_session cookie.

required
csrf_token str

URL-decoded value of the _csrf_token cookie. Required for writes (Canvas checks it against the X-CSRF-Token header); may be empty for read-only use.

required
source str

File the cookies were read from.

required
browser_source BrowserSource | None

Browser and profile to refresh an imported session from.

None
description property
description: str

Short human label for status output.

parse_creds
parse_creds(
    text: str,
    source: str = CREDS_FILENAME,
    *,
    path: Path | None = None,
) -> SessionAuth

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 canvas_session is missing.

find_auth
find_auth(root: Path) -> CanvasAuth | None

Locate Canvas credentials for the project at root.

Order: .canvastoken, .canvascreds (session cookie), $CANVAS_TOKEN.

Returns:

Type Description
CanvasAuth | None

The configured auth, or None if nothing usable was found.

check_request
check_request(auth: CanvasAuth, request: Request) -> None

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
check_response(
    auth: CanvasAuth, response: Response
) -> None

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_browser_session(source: BrowserSource) -> SessionAuth

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
save_browser_session(auth: SessionAuth) -> None

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.

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,
)

Typed Canvas LMS API client with course_id baked in.

Parameters:

Name Type Description Default
base_url str | None

Canvas instance URL (e.g. https://canvas.ucsd.edu).

None
token str | None

Canvas API bearer token (shortcut for auth=TokenAuth(...)).

None
course_id int | None

Canvas course ID for all requests.

None
auth CanvasAuth | None

Credentials to use; defaults to whatever get_auth finds.

None
transport BaseTransport | None

HTTP transport override (tests inject a mock here).

None
time_zone str | None

IANA course time zone; defaults to [canvas] time_zone in cass.toml and is fetched from the course when that is empty.

None
time_zone property
time_zone: str

IANA time zone of the course (from cass.toml, else fetched once).

close
close() -> None

Close the underlying HTTP client.

request
request(
    method: str, path: str, **kwargs: Any
) -> httpx.Response

Send any request with cass's auth and retry handling.

Use self._course(path) for course-relative paths. Raises httpx.HTTPStatusError on a 4xx/5xx response.

publish
publish(resource: str, resource_id: int) -> None

Publish a resource (module, assignment, or quiz).

Parameters:

Name Type Description Default
resource str

Resource type (modules, assignments, quizzes).

required
resource_id int

Canvas resource ID.

required
unpublish
unpublish(resource: str, resource_id: int) -> None

Unpublish a resource (module, assignment, or quiz).

Parameters:

Name Type Description Default
resource str

Resource type (modules, assignments, quizzes).

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 CanvasAuthError with instructions to fix them.

required
retries int

Connection-level retries for the underlying HTTP transport.

0
wrapped BaseTransport | None

Transport to delegate to (defaults to httpx.HTTPTransport; tests pass an httpx.MockTransport).

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,
)

Bases: CourseMixin, ModulesMixin, 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
get_auth() -> CanvasAuth

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
get_token() -> str

Read the Canvas API token from .canvastoken or $CANVAS_TOKEN.

Raises:

Type Description
SystemExit

If no token is found.

resource_key
resource_key(resource: str) -> str

Map a plural resource name to Canvas API parameter key.

save_token
save_token(token: str) -> None

Write a Canvas API token to .canvastoken.

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,
)

Bases: BaseClient

Announcements (discussion topics flagged as announcements).

list_announcements
list_announcements() -> list[CanvasAnnouncement]

List course announcements.

Returns:

Type Description
list[CanvasAnnouncement]

Announcements sorted by posted_at descending.

create_announcement
create_announcement(
    title: str, message: str
) -> CanvasAnnouncement

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_announcement
update_announcement(
    topic_id: int, **kwargs: object
) -> CanvasAnnouncement

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.

delete_announcement
delete_announcement(topic_id: int) -> None

Delete an 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,
)

Bases: BaseClient

Assignments and assignment groups.

list_assignments
list_assignments() -> list[CanvasAssignmentResponse]

List all course assignments.

Returns:

Type Description
list[CanvasAssignmentResponse]

Assignments from all assignment groups.

get_assignment
get_assignment(
    assignment_id: int,
) -> CanvasAssignmentResponse

Get a single assignment by ID.

create_assignment
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_assignment
update_assignment(
    assignment_id: int, **kwargs: object
) -> CanvasAssignmentResponse

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.

delete_assignment
delete_assignment(assignment_id: int) -> None

Delete an assignment.

list_assignment_groups
list_assignment_groups() -> list[CanvasAssignmentGroup]

List assignment groups (grade categories).

Returns:

Type Description
list[CanvasAssignmentGroup]

Assignment groups with weights and rules.

create_assignment_group
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_assignment_group
delete_assignment_group(group_id: int) -> None

Delete an assignment group (Canvas also deletes its assignments).

resolve_assignment_group
resolve_assignment_group(
    id_or_name: str,
) -> CanvasAssignmentGroup

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_assignment
resolve_assignment(
    id_or_name: str,
) -> CanvasAssignmentResponse

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 CanvasAuthError with instructions to fix them.

required
retries int

Connection-level retries for the underlying HTTP transport.

0
wrapped BaseTransport | None

Transport to delegate to (defaults to httpx.HTTPTransport; tests pass an httpx.MockTransport).

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,
)

Typed Canvas LMS API client with course_id baked in.

Parameters:

Name Type Description Default
base_url str | None

Canvas instance URL (e.g. https://canvas.ucsd.edu).

None
token str | None

Canvas API bearer token (shortcut for auth=TokenAuth(...)).

None
course_id int | None

Canvas course ID for all requests.

None
auth CanvasAuth | None

Credentials to use; defaults to whatever get_auth finds.

None
transport BaseTransport | None

HTTP transport override (tests inject a mock here).

None
time_zone str | None

IANA course time zone; defaults to [canvas] time_zone in cass.toml and is fetched from the course when that is empty.

None
time_zone property
time_zone: str

IANA time zone of the course (from cass.toml, else fetched once).

close
close() -> None

Close the underlying HTTP client.

request
request(
    method: str, path: str, **kwargs: Any
) -> httpx.Response

Send any request with cass's auth and retry handling.

Use self._course(path) for course-relative paths. Raises httpx.HTTPStatusError on a 4xx/5xx response.

publish
publish(resource: str, resource_id: int) -> None

Publish a resource (module, assignment, or quiz).

Parameters:

Name Type Description Default
resource str

Resource type (modules, assignments, quizzes).

required
resource_id int

Canvas resource ID.

required
unpublish
unpublish(resource: str, resource_id: int) -> None

Unpublish a resource (module, assignment, or quiz).

Parameters:

Name Type Description Default
resource str

Resource type (modules, assignments, quizzes).

required
resource_id int

Canvas resource ID.

required
get_auth
get_auth() -> CanvasAuth

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
get_token() -> str

Read the Canvas API token from .canvastoken or $CANVAS_TOKEN.

Raises:

Type Description
SystemExit

If no token is found.

save_token
save_token(token: str) -> None

Write a Canvas API token to .canvastoken.

resource_key
resource_key(resource: str) -> str

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,
)

Bases: BaseClient

Course calendar events.

list_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
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_calendar_event
update_calendar_event(
    event_id: int, **kwargs: object
) -> CanvasCalendarEvent

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.

delete_calendar_event
delete_calendar_event(event_id: int) -> None

Delete a calendar 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,
)

Bases: BaseClient

Course, people, sections, enrollments, and grading standards.

get_course
get_course() -> CanvasCourse

Get course details.

Returns:

Type Description
CanvasCourse

Course metadata.

list_users
list_users(
    enrollment_type: str | None = None,
) -> list[CanvasUser]

List course users with enrollments.

Parameters:

Name Type Description Default
enrollment_type str | None

Filter by role (e.g. student, teacher).

None

Returns:

Type Description
list[CanvasUser]

Users sorted by name.

list_students
list_students() -> list[CanvasStudentResponse]

List students enrolled in the course.

Returns:

Type Description
list[CanvasStudentResponse]

Students sorted by Canvas enrollment order.

list_sections
list_sections() -> list[CanvasSection]

List all course sections.

Returns:

Type Description
list[CanvasSection]

Sections with SIS IDs (if available).

list_enrollments
list_enrollments(
    *, enrollment_type: str = "StudentEnrollment"
) -> list[CanvasEnrollment]

List enrollments with computed scores.

Parameters:

Name Type Description Default
enrollment_type str

Filter by type (default: StudentEnrollment).

'StudentEnrollment'

Returns:

Type Description
list[CanvasEnrollment]

Enrollments including computed_final_score.

list_grading_standards
list_grading_standards() -> list[CanvasGradingStandard]

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,
)

Bases: BaseClient

Files and folders.

list_files
list_files(
    folder_id: int | None = None,
) -> list[CanvasFile]

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.

list_folders
list_folders() -> list[CanvasFolder]

List all folders in the course.

Returns:

Type Description
list[CanvasFolder]

Folders with hierarchy info.

upload_file
upload_file(
    local_path: str, *, folder: str = ""
) -> 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 in Canvas (e.g. course files/slides).

''

Returns:

Type Description
CanvasFile

The uploaded file metadata.

delete_file
delete_file(file_id: int) -> None

Delete a file.

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,
)

Bases: BaseClient

Submissions, grade pushes, progress polling, and grade posting.

list_submissions
list_submissions(
    assignment_id: int,
) -> list[CanvasSubmissionResponse]

List submissions for an assignment.

Parameters:

Name Type Description Default
assignment_id int

Canvas assignment ID.

required

Returns:

Type Description
list[CanvasSubmissionResponse]

All submissions for the assignment.

push_grade
push_grade(
    assignment_id: int, student_canvas_id: int, grade: str
) -> bool

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.

bulk_push_grades
bulk_push_grades(
    assignment_id: int, grade_data: dict[int, str]
) -> CanvasProgress

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_progress
check_progress(progress_id: int) -> CanvasProgress

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.

wait_for_progress
wait_for_progress(
    progress_id: int, *, timeout: float = 120.0
) -> CanvasProgress

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_assignment_grades
post_assignment_grades(
    assignment_id: int, *, graded_only: bool = True
) -> CanvasProgress | None

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_assignment_grades
hide_assignment_grades(
    assignment_id: int,
) -> CanvasProgress | None

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,
)

Bases: BaseClient

Modules and module items.

list_modules
list_modules() -> list[CanvasModule]

List all course modules.

Returns:

Type Description
list[CanvasModule]

Modules sorted by position.

get_module
get_module(module_id: int) -> CanvasModule

Get a single module by ID.

list_module_items
list_module_items(module_id: int) -> list[CanvasModuleItem]

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_module
create_module(
    name: str, position: int | None = None
) -> CanvasModule

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_module
update_module(
    module_id: int, **kwargs: object
) -> CanvasModule

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.

delete_module
delete_module(module_id: int) -> None

Delete a module.

create_module_item
create_module_item(
    module_id: int,
    *,
    item_type: str,
    content_id: int,
    title: str | None = None,
) -> CanvasModuleItem

Add an item to a module.

Parameters:

Name Type Description Default
module_id int

Canvas module ID.

required
item_type str

Item type (Assignment, Quiz, File, etc.).

required
content_id int

ID of the linked content.

required
title str | None

Item title; Canvas uses the content's name when omitted.

None

Returns:

Type Description
CanvasModuleItem

The created module item.

resolve_module
resolve_module(id_or_name: str) -> CanvasModule

Resolve a module by numeric ID or name (case-insensitive).

Raises:

Type Description
RuntimeError

If no module matches.

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,
)

Bases: BaseClient

Classic quizzes and quiz questions.

list_quizzes
list_quizzes() -> list[CanvasQuiz]

List all course quizzes.

Returns:

Type Description
list[CanvasQuiz]

Quizzes of all types.

get_quiz
get_quiz(quiz_id: int) -> CanvasQuiz

Get a single quiz by ID.

create_quiz
create_quiz(
    spec: QuizSpec,
    *,
    assignment_group_id: int | None = None,
) -> CanvasQuiz

Create a quiz with its questions.

Posts the quiz unpublished, posts each question in order, 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
update_quiz(
    quiz_id: int, changes: dict[str, object]
) -> CanvasQuiz

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 quiz_settings_diff).

required

Returns:

Type Description
CanvasQuiz

The updated quiz.

list_quiz_questions
list_quiz_questions(
    quiz_id: int,
) -> tuple[list[CanvasQuizQuestion], bool]

List a quiz's questions in position order.

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]

(questions, used_statistics_fallback).

create_quiz_question
create_quiz_question(
    quiz_id: int,
    question: QuestionSpec,
    position: int,
    *,
    quiz_type: str = "assignment",
) -> CanvasQuizQuestion

Add one question to a quiz.

Parameters:

Name Type Description Default
quiz_id int

Canvas quiz ID.

required
question QuestionSpec

Question spec; points None uses the type default.

required
position int

1-based position; also the default name (Question N).

required
quiz_type str

Decides the default points (0 for surveys, else 1).

'assignment'

Returns:

Type Description
CanvasQuizQuestion

The created question.

delete_quiz
delete_quiz(quiz_id: int) -> None

Delete a quiz.

create_quiz_report
create_quiz_report(
    quiz_id: int, *, all_versions: bool = False
) -> CanvasQuizReport

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; file is None until generation finishes.

get_quiz_report
get_quiz_report(
    quiz_id: int, report_id: int
) -> CanvasQuizReport

Get a quiz report with its file and progress.

download_quiz_report
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_quiz_submissions
list_quiz_submissions(
    quiz_id: int,
) -> list[CanvasQuizSubmission]

List each student's latest attempt on a quiz.

Returns:

Type Description
list[CanvasQuizSubmission]

One quiz submission per student who opened the quiz.

resolve_quiz
resolve_quiz(id_or_name: str) -> CanvasQuiz

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,
)

Bases: BaseClient

Course navigation tabs.

list_tabs
list_tabs() -> list[CanvasTab]

List course navigation tabs.

Returns:

Type Description
list[CanvasTab]

Tabs with visibility and position.

update_tab
update_tab(tab_id: str, *, hidden: bool) -> CanvasTab

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_tab
resolve_tab(id_or_label: str) -> CanvasTab

Resolve a navigation tab by ID (e.g. syllabus) or label.

Raises:

Type Description
RuntimeError

If no tab matches.

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
score_to_letter(
    pct: float | None,
    scheme: list[CanvasGradingSchemeEntry],
) -> str

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 "" if score is None or scheme is empty.

parse_sortable_name
parse_sortable_name(sortable_name: str) -> tuple[str, str]

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_egrades(
    output: str | Path = "egrades.csv",
) -> tuple[Path, int, list[str]]

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.

matching

Canvas LMS integration — roster fetching, submission retrieval, and grade push.

All raw API calls are delegated to CanvasClient in client.py.

get_token
get_token() -> str

Read the Canvas API token from .canvastoken or $CANVAS_TOKEN.

Raises:

Type Description
SystemExit

If no token is found.

save_token
save_token(token: str) -> None

Write a Canvas API token to .canvastoken.

fetch_students
fetch_students(
    course_id: int,
) -> list[CanvasStudentResponse]

Fetch all students enrolled in a Canvas course.

fetch_course_name
fetch_course_name(course_id: int) -> str

Fetch the course name from the Canvas API.

fetch_course_time_zone
fetch_course_time_zone() -> str

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_grade(
    course_id: int,
    assignment_id: int,
    student_canvas_id: int,
    grade: str,
) -> bool

Push a single grade to Canvas. Returns True on success, False on failure.

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

Bases: Struct

Canvas enrollment record.

computed_final_score property
computed_final_score: float | None

Canvas returns final_score nested inside grades dict.

computed_current_score property
computed_current_score: float | None

Canvas returns current_score nested inside grades dict.

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.

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.

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
same_instant(a: str | None, b: str | None) -> bool

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
values_equal(a: object, b: object) -> bool

Compare values loosely, handling datetime/string equivalence.

resolve_row_name
resolve_row_name(
    conn: Database, table: str, pk_key: str
) -> str

Resolve a pending-change pk_key to a human-readable row name.

is_valid_grade
is_valid_grade(grade: str | None) -> bool

Return True if grade is non-empty and not a placeholder.

build_grade_push_data
build_grade_push_data(
    grades: list[CanvasGrade],
) -> tuple[dict[int, dict[int, str]], int]

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
get_post_manually_map(conn: Database) -> dict[int, bool]

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 name, canvas_id, count, post_manually.

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]]

{assignment_id: {user_id: grade_string}}.

required

Returns:

Type Description
list[dict[str, object]]

List of result dicts with ok, canvas_assignment_id, count,

list[dict[str, object]]

and optionally error or action keys.

resolve_group_ids
resolve_group_ids(
    client: CanvasClient, names: Iterable[str]
) -> tuple[dict[str, int], list[str]]

Map assignment group names to IDs, case-insensitively.

Returns:

Type Description
tuple[dict[str, int], list[str]]

(ids keyed by lower-cased name, names with no live match).

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]]

{canvas_assignment_id: {field: new_value}}.

required

Returns:

Type Description
list[dict[str, object]]

List of result dicts with ok, canvas_id, and optionally error.

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_when(value: str, tz: str) -> str

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.

format_when
format_when(
    iso: str | None, tz: str, *, date_only: bool = False
) -> str

Render an ISO instant in tz as YYYY-MM-DD HH:MM (or the date).

same_instant
same_instant(a: str | None, b: str | None) -> bool

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.