API Reference

Configuration helpers.

course_hoanganhduc.config.cache_course_code(course_code)[source]

Persist a normalized course code in the local .course_code cache.

course_hoanganhduc.config.clear_config(config_path=None, course_code=None, verbose=False)[source]

Remove the stored config file.

course_hoanganhduc.config.clear_credentials(credentials_path=None, token_path=None, course_code=None, verbose=False)[source]

Remove stored credentials and token files.

course_hoanganhduc.config.get_cached_course_code()[source]

Return the cached course code from .course_code if available.

course_hoanganhduc.config.get_config_base_dir()[source]

Get the directory that holds one config folder per course, without creating anything. - Windows: %APPDATA%course - macOS: ~/Library/Application Support/course - Linux: ~/.config/course

course_hoanganhduc.config.get_default_config_path(course_code=None, verbose=False)[source]

Get the default config file path for the current operating system. The course_code controls the subfolder name under the base config directory. - Windows: %APPDATA%course<course_code>config.json - macOS: ~/Library/Application Support/course/<course_code>/config.json - Linux: ~/.config/course/<course_code>/config.json If verbose is True, print details about the chosen path. Otherwise, print only an important notice if the config file does not exist.

course_hoanganhduc.config.get_default_credentials_path(course_code=None, verbose=False)[source]

Get the default credentials file path alongside the config file.

course_hoanganhduc.config.get_default_download_folder(verbose=False)[source]

Get the default download folder for the current operating system. Returns the Downloads folder path appropriate for Windows, Mac, or Linux. If verbose is True, print details about the chosen path. Otherwise, print only an important notice if the folder does not exist.

course_hoanganhduc.config.get_default_token_path(course_code=None, verbose=False)[source]

Get the default token file path alongside the config file.

course_hoanganhduc.config.load_config(config_path=None, verbose=False)[source]

Load configuration from a JSON or base64-encoded JSON file at the default location and return config values as a dict. If config_path is not provided, loads from the OS-specific default location. config_path can be a file path (JSON or base64-encoded JSON) or a base64 string. Returns a dict of the loaded config values (does NOT set global variables). If verbose is True, print more details; otherwise, print only important notice.

NOTE: If you want to update global variables, you must set:

DEFAULT_AI_METHOD ALL_AI_METHODS GEMINI_API_KEY HUGGINGFACE_API_KEY GEMINI_DEFAULT_MODEL DEFAULT_OCR_METHOD ALL_OCR_METHODS OCRSPACE_API_KEY OCRSPACE_API_URL LOCAL_LLM_COMMAND LOCAL_LLM_MODEL LOCAL_LLM_ARGS LOCAL_LLM_TIMEOUT CANVAS_LMS_API_URL CANVAS_LMS_API_KEY CANVAS_LMS_COURSE_ID GOOGLE_CLASSROOM_GRADE_CATEGORY_METHOD GOOGLE_CLASSROOM_CC_TOPICS GOOGLE_CLASSROOM_GK_TOPICS GOOGLE_CLASSROOM_CK_TOPICS GOOGLE_SHEET_URL COURSE_CODE COURSE_NAME DEFAULT_RESTRICTED WEIGHT_CC WEIGHT_GK WEIGHT_CK QUALITY_MIN_CHARS QUALITY_UNIQUE_CHAR_RATIO_MIN QUALITY_REPEAT_CHAR_RATIO_MAX QUALITY_VN_CHAR_RATIO_MIN QUALITY_ALNUM_RATIO_MIN QUALITY_SYMBOL_RATIO_MAX QUALITY_EMPTY_LINE_RATIO_MAX QUALITY_MATH_DENSITY_THRESHOLD QUALITY_LENGTH_RATIO_LOW QUALITY_LENGTH_RATIO_MEDIUM QUALITY_LENGTH_RATIO_HIGH MIDTERM_DATE EXAM_TYPE CANVAS_MIDTERM_ASSIGNMENT_ID CANVAS_FINAL_ASSIGNMENT_ID CANVAS_CC_ASSIGNMENT_ID

course_hoanganhduc.config.validate_config(config, verbose=False)[source]

Lightweight validation for config values. Returns a list of warning strings.

Canvas LMS helpers.

course_hoanganhduc.canvas.interactive_modify_database(students, db_path=None, verbose=False)[source]

Interactively modify student records in the database. Allows searching, editing, adding, and deleting students. When editing a field, pre-fill the old value for easy modification. After editing a field, ask if the user wants to continue editing other fields of the same student, edit another student, or quit. Always allow quitting at any step. If no response after 60 seconds from user then quit. If verbose is True, print more details; otherwise, print only important notice.

exception course_hoanganhduc.google_classroom.CredentialSecurityError[source]

Credential location, metadata, or content is unsafe.

exception course_hoanganhduc.google_classroom.GoogleClassroomAPIError(operation, *, status=None)[source]

A definite, sanitized Google API failure.

Parameters:
  • operation (str)

  • status (Optional[int])

exception course_hoanganhduc.google_classroom.GoogleClassroomError[source]

Base error for the isolated coursework creation surface.

exception course_hoanganhduc.google_classroom.GoogleClassroomOutcomeUnknownError(operation, course_id, *, status=None)[source]

A create request may have succeeded, but no resource ID is known.

Parameters:
  • operation (str)

  • course_id (str)

  • status (Optional[int])

exception course_hoanganhduc.google_classroom.GoogleClassroomPartialCreateError(*, stage, course_id, course_work_id, alternate_link=None, rubric_created=None, intended_release='DRAFT', observed_course_work=None, status=None)[source]

Coursework exists but a rubric or release stage did not complete.

Parameters:
  • stage (str)

  • course_id (str)

  • course_work_id (str)

  • alternate_link (Optional[str])

  • rubric_created (Optional[bool])

  • intended_release (str)

  • observed_course_work (Optional[Mapping[str, Any]])

  • status (Optional[int])

course_hoanganhduc.google_classroom.build_google_classroom_assignment_body(title, *, description=None, state='DRAFT', scheduled_at=None, due_at=None, max_points=None, materials=None, assignee_mode='ALL_STUDENTS', individual_student_ids=None, submission_modification_mode='MODIFIABLE_UNTIL_TURNED_IN', topic_id=None, grading_period_mode='AUTO', grading_period_id=None, now=None)[source]

Build and validate a stable REST v1 ASSIGNMENT request body.

Parameters:
  • title (str)

  • description (str | None)

  • state (str)

  • scheduled_at (str | datetime | None)

  • due_at (str | datetime | None)

  • max_points (int | None)

  • materials (Sequence[Mapping[str, Any]] | None)

  • assignee_mode (str)

  • individual_student_ids (Sequence[str] | None)

  • submission_modification_mode (str)

  • topic_id (str | None)

  • grading_period_mode (str)

  • grading_period_id (str | None)

  • now (datetime | None)

Return type:

Dict[str, Any]

course_hoanganhduc.google_classroom.build_google_classroom_rubric_body(criteria, *, scoring_mode)[source]

Build an inline rubric body; spreadsheet-backed rubrics are not accepted.

Parameters:
  • criteria (Sequence[Mapping[str, Any]])

  • scoring_mode (str)

Return type:

Dict[str, Any]

course_hoanganhduc.google_classroom.create_google_classroom_assignment(service, course_id, body)[source]

Create one assignment with no automatic retry.

Parameters:
  • service (Any)

  • course_id (str)

  • body (Mapping[str, Any])

Return type:

Dict[str, Any]

course_hoanganhduc.google_classroom.create_google_classroom_assignment_with_rubric(service, course_id, assignment_body, rubric_body=None, *, schedule_min_lead_seconds=60, now=None)[source]

Create coursework, optionally attach a rubric, then publish or schedule it.

Parameters:
  • service (Any)

  • course_id (str)

  • assignment_body (Mapping[str, Any])

  • rubric_body (Mapping[str, Any] | None)

  • schedule_min_lead_seconds (int)

  • now (datetime | Callable[[], datetime] | None)

Return type:

Dict[str, Any]

course_hoanganhduc.google_classroom.download_google_classroom_assignment_submissions(course_id=None, credentials_path='gclassroom_credentials.json', token_path='token.pickle', coursework_ids=None, dest_dir=None, ocr_service='ocrspace', lang='auto', meaningfulness_threshold=0.4, similarity_threshold=0.85, verbose=False)[source]

Download latest Google Classroom submissions for selected coursework, then run meaningfulness + similarity checks on PDFs.

course_hoanganhduc.google_classroom.download_google_sheet_to_csv(sheet_url, output_path=None, credentials_path='gclassroom_credentials.json', token_path='token.pickle', verbose=False, sheet_name=None, sheet_selection='first')[source]

Download a Google Sheet as CSV using the first sheet, gid in URL, or specified sheet. Returns the output CSV path.

Parameters:
  • sheet_name – Specific sheet name to download

  • sheet_selection – Mode for sheet selection - ‘first’ (default), ‘select’ (interactive), ‘all’, or ‘merge’

course_hoanganhduc.google_classroom.get_google_classroom_auth_status(paths, *, show_paths=False)[source]

Inspect credential metadata without refresh, OAuth, network, or writes.

Parameters:
Return type:

Dict[str, Any]

course_hoanganhduc.google_classroom.get_google_classroom_coursework_service(paths, *, expected_account, open_browser=None, force_authorize=False, replace_token=False, require_existing_token=False, timeout_seconds=300, profile_timeout_seconds=30, service_builder=None, profile_fetcher=None)[source]

Load/authorize a token, verify its principal, and build one Classroom service.

Parameters:
  • paths (CourseworkAuthPaths)

  • expected_account (str)

  • open_browser (bool | None)

  • force_authorize (bool)

  • replace_token (bool)

  • require_existing_token (bool)

  • timeout_seconds (int)

  • profile_timeout_seconds (int)

  • service_builder (Any | None)

  • profile_fetcher (Any | None)

Return type:

CourseworkAuthSession

course_hoanganhduc.google_classroom.grade_google_classroom_assignment_submissions(course_id=None, credentials_path='gclassroom_credentials.json', token_path='token.pickle', coursework_ids=None, score=None, ungraded_only=True, apply_all=False, verbose=False)[source]

Grade Google Classroom assignment submissions interactively or with provided IDs. - If coursework_ids is None, prompt for selection. - If score is None, prompt for a score and apply to selected submissions. - If ungraded_only is True, only list ungraded submissions.

course_hoanganhduc.google_classroom.invite_students_to_google_classroom(course_id=None, emails=None, domains=None, section=None, class_name=None, role='STUDENT', apply_all=False, credentials_path='gclassroom_credentials.json', token_path='token.pickle', db_path=None, update_local_db=True, dry_run=False, verbose=False, service=None, sleep_fn=None, profile_lookup_limit=200)[source]

Invite local-database students to a Google Classroom course.

Students already enrolled, already teaching, or already holding a pending invitation are skipped, so re-running the command is safe and quiet. Returns a summary dict; see the module docstring for the departures from the unenroll template.

course_hoanganhduc.google_classroom.resolve_coursework_auth_paths(account, *, credentials_path=None, token_path=None, env=None, platform_system=None, home=None)[source]

Resolve one deterministic CLI, environment, or default credential pair.

Parameters:
  • account (str)

  • credentials_path (str | None)

  • token_path (str | None)

  • env (Mapping[str, str] | None)

  • platform_system (str | None)

  • home (Path | None)

Return type:

CourseworkAuthPaths

course_hoanganhduc.google_classroom.sync_students_with_google_classroom(students, db_path=None, course_id=None, credentials_path='gclassroom_credentials.json', token_path='token.pickle', fetch_grades=False, verbose=False)[source]

Sync students in the local database with active students from Google Classroom. For each student fetched from Google Classroom:

  • match by Google_ID first, then by display name, name or email (case-insensitive)

  • if matched: fill missing local fields from Google data (Google_ID, Email, Google_Classroom_Display_Name)

  • if not matched: create a new student entry with Name, Email, Google_ID and Google_Classroom_Display_Name

Optionally fetch grades/submission state when fetch_grades=True.

Rows the course no longer contains are reported, never removed: only the teacher can tell a student who has left from one who filled the form before being enrolled.

Returns (added_count, updated_count).

course_hoanganhduc.google_classroom.unenroll_google_classroom_students(course_id=None, domains=None, emails=None, select_all=False, select_mode=False, credentials_path='gclassroom_credentials.json', token_path='token.pickle', apply_all=False, missing_student_id=False, db_path=None, update_local_db=True, dry_run=False, verbose=False)[source]

Unenroll students from a Google Classroom course by email domain.

Google Classroom assignment creation

Google Classroom assignment builders and mutation orchestration.

The builders are dependency-free. API functions accept a discovery-style service object so tests can run without Google packages or credentials.

exception course_hoanganhduc.gclass_coursework.GoogleClassroomAPIError(operation, *, status=None)[source]

A definite, sanitized Google API failure.

Parameters:
  • operation (str)

  • status (Optional[int])

exception course_hoanganhduc.gclass_coursework.GoogleClassroomError[source]

Base error for the isolated coursework creation surface.

exception course_hoanganhduc.gclass_coursework.GoogleClassroomOutcomeUnknownError(operation, course_id, *, status=None)[source]

A create request may have succeeded, but no resource ID is known.

Parameters:
  • operation (str)

  • course_id (str)

  • status (Optional[int])

exception course_hoanganhduc.gclass_coursework.GoogleClassroomPartialCreateError(*, stage, course_id, course_work_id, alternate_link=None, rubric_created=None, intended_release='DRAFT', observed_course_work=None, status=None)[source]

Coursework exists but a rubric or release stage did not complete.

Parameters:
  • stage (str)

  • course_id (str)

  • course_work_id (str)

  • alternate_link (Optional[str])

  • rubric_created (Optional[bool])

  • intended_release (str)

  • observed_course_work (Optional[Mapping[str, Any]])

  • status (Optional[int])

course_hoanganhduc.gclass_coursework.build_google_classroom_assignment_body(title, *, description=None, state='DRAFT', scheduled_at=None, due_at=None, max_points=None, materials=None, assignee_mode='ALL_STUDENTS', individual_student_ids=None, submission_modification_mode='MODIFIABLE_UNTIL_TURNED_IN', topic_id=None, grading_period_mode='AUTO', grading_period_id=None, now=None)[source]

Build and validate a stable REST v1 ASSIGNMENT request body.

Parameters:
  • title (str)

  • description (str | None)

  • state (str)

  • scheduled_at (str | datetime | None)

  • due_at (str | datetime | None)

  • max_points (int | None)

  • materials (Sequence[Mapping[str, Any]] | None)

  • assignee_mode (str)

  • individual_student_ids (Sequence[str] | None)

  • submission_modification_mode (str)

  • topic_id (str | None)

  • grading_period_mode (str)

  • grading_period_id (str | None)

  • now (datetime | None)

Return type:

Dict[str, Any]

course_hoanganhduc.gclass_coursework.build_google_classroom_rubric_body(criteria, *, scoring_mode)[source]

Build an inline rubric body; spreadsheet-backed rubrics are not accepted.

Parameters:
  • criteria (Sequence[Mapping[str, Any]])

  • scoring_mode (str)

Return type:

Dict[str, Any]

course_hoanganhduc.gclass_coursework.create_google_classroom_assignment(service, course_id, body)[source]

Create one assignment with no automatic retry.

Parameters:
  • service (Any)

  • course_id (str)

  • body (Mapping[str, Any])

Return type:

Dict[str, Any]

course_hoanganhduc.gclass_coursework.create_google_classroom_assignment_with_rubric(service, course_id, assignment_body, rubric_body=None, *, schedule_min_lead_seconds=60, now=None)[source]

Create coursework, optionally attach a rubric, then publish or schedule it.

Parameters:
  • service (Any)

  • course_id (str)

  • assignment_body (Mapping[str, Any])

  • rubric_body (Mapping[str, Any] | None)

  • schedule_min_lead_seconds (int)

  • now (datetime | Callable[[], datetime] | None)

Return type:

Dict[str, Any]

Isolated credentials for human Google Classroom coursework mutations.

This module intentionally does not reuse the legacy pickle token or course-scoped credential resolver. Google dependencies are imported only when online auth starts.

class course_hoanganhduc.gclass_coursework_auth.CourseworkAuthPaths(account: 'str', account_fingerprint: 'str', credentials_path: 'Optional[Path]', token_path: 'Path', metadata_path: 'Path', source: 'str', token_only: 'bool')[source]
Parameters:
  • account (str)

  • account_fingerprint (str)

  • credentials_path (Path | None)

  • token_path (Path)

  • metadata_path (Path)

  • source (str)

  • token_only (bool)

class course_hoanganhduc.gclass_coursework_auth.CourseworkAuthSession(service: 'Any', profile: 'Mapping[str, Any]', paths: 'CourseworkAuthPaths', client_id_fingerprint: 'str')[source]
Parameters:
  • service (Any)

  • profile (Mapping[str, Any])

  • paths (CourseworkAuthPaths)

  • client_id_fingerprint (str)

exception course_hoanganhduc.gclass_coursework_auth.CredentialSecurityError[source]

Credential location, metadata, or content is unsafe.

class course_hoanganhduc.gclass_coursework_auth.TokenFileLock(token_path)[source]

Nonblocking POSIX lock preventing concurrent token refresh/write.

Parameters:

token_path (Path)

exception course_hoanganhduc.gclass_coursework_auth.UnsupportedPlatformCredentialSecurityError[source]

Native credential guarantees are not implemented for this platform.

course_hoanganhduc.gclass_coursework_auth.get_google_classroom_auth_status(paths, *, show_paths=False)[source]

Inspect credential metadata without refresh, OAuth, network, or writes.

Parameters:
Return type:

Dict[str, Any]

course_hoanganhduc.gclass_coursework_auth.get_google_classroom_coursework_service(paths, *, expected_account, open_browser=None, force_authorize=False, replace_token=False, require_existing_token=False, timeout_seconds=300, profile_timeout_seconds=30, service_builder=None, profile_fetcher=None)[source]

Load/authorize a token, verify its principal, and build one Classroom service.

Parameters:
  • paths (CourseworkAuthPaths)

  • expected_account (str)

  • open_browser (bool | None)

  • force_authorize (bool)

  • replace_token (bool)

  • require_existing_token (bool)

  • timeout_seconds (int)

  • profile_timeout_seconds (int)

  • service_builder (Any | None)

  • profile_fetcher (Any | None)

Return type:

CourseworkAuthSession

course_hoanganhduc.gclass_coursework_auth.resolve_coursework_auth_paths(account, *, credentials_path=None, token_path=None, env=None, platform_system=None, home=None)[source]

Resolve one deterministic CLI, environment, or default credential pair.

Parameters:
  • account (str)

  • credentials_path (str | None)

  • token_path (str | None)

  • env (Mapping[str, str] | None)

  • platform_system (str | None)

  • home (Path | None)

Return type:

CourseworkAuthPaths

Google Classroom assignment administration CLI.

The mutation surface is deliberately separate from the legacy course CLI and the restricted agent entrypoint. Assignment JSON is converted into a canonical request before any credential access or network call.

exception course_hoanganhduc.gclass_admin_cli.AssignmentSpecError[source]

The local assignment specification is malformed or unsupported.

exception course_hoanganhduc.gclass_admin_cli.GoogleClassroomAdminError[source]

An assignment-admin precondition or confirmation failed.

course_hoanganhduc.gclass_admin_cli.build_assignment_operation_plan(course_reference, assignment, rubric, *, dry_run=True)[source]

Build the deterministic preview and confirmation digest for one mutation.

Parameters:
  • course_reference (str)

  • assignment (Mapping[str, Any])

  • rubric (Mapping[str, Any] | None)

  • dry_run (bool)

Return type:

Dict[str, Any]

course_hoanganhduc.gclass_admin_cli.load_assignment_spec(path, *, now=None)[source]

Load a strict JSON spec and return canonical assignment and rubric bodies.

Parameters:
  • path (Path)

  • now (datetime | None)

Return type:

Tuple[Dict[str, Any], Dict[str, Any] | None]

course_hoanganhduc.gclass_admin_cli.main(argv=None, *, input_fn=<built-in function input>, stdout=None, stderr=None, tty_check=None, auth_factory=None, create_factory=None, secret_input_fn=None, loopback_connection_factory=None, now=None)[source]

Run the dedicated admin CLI; dependency injection keeps tests offline.

Parameters:
  • argv (Sequence[str] | None)

  • input_fn (Callable[[str], str])

  • stdout (TextIO | None)

  • stderr (TextIO | None)

  • tty_check (Callable[[], bool] | None)

  • auth_factory (Callable[[...], Any] | None)

  • create_factory (Callable[[...], Dict[str, Any]] | None)

  • secret_input_fn (Callable[[str], str] | None)

  • loopback_connection_factory (Callable[[...], Any] | None)

  • now (datetime | None)

Return type:

int

Agent and Classroom50 modules

These modules support the restricted agent surfaces and Classroom50 adapter. Prefer the CLI entrypoints documented in Usage over calling them as a public Python API unless you are extending the toolkit.

  • course_hoanganhduc.classroom50 — agent-safe Classroom50 facade

  • course_hoanganhduc.c50_agent / c50_flags / c50_ops / c50_cli

  • course_hoanganhduc.canvas_agent

  • course_hoanganhduc.gclass_agent

  • course_hoanganhduc.db_agent

  • course_hoanganhduc.course_agent_common — agent mode + allowlist helpers