Python client and CLI for KULMS/Sakai Direct API
Project description
kulms
kulms は、京都大学の学習支援システム KULMS にアクセスするための Python クライアントと CLI です。KULMS は Sakai LMS 互換の環境です。
Sakai Direct API を直接扱う代わりに、授業、授業資料、課題、お知らせ、カレンダーなど、KULMS の利用者が画面上で見慣れた単位で操作できる API と CLI を提供します。専用 API がまだない Direct API も client.direct や kulms direct から直接呼び出せます。
使い方
CLI として使うだけなら、基本の流れは次の通りです。
uv tool install kulms
uv tool update-shell
kulms auth login
kulms courses
kulms assignments
kulms courses に表示される ID を使うと、授業資料を一覧表示したりダウンロードしたりできます。
kulms resources COURSE_ID
kulms resources COURSE_ID --download
Python ライブラリとして使う場合は python -m pip install kulms を使ってください。uv を使わない場合は pipx install kulms でも CLI をインストールできます。
主な機能
- kuauth を使って KULMS にログインできます。
- ユーザー名、パスワード、TOTP シークレットを keyring に保存できます。
- セッション Cookie をユーザーキャッシュディレクトリに保存し、通常の CLI 操作では再ログインせずに使い回せます。
- コース一覧、コース詳細、コースのタブ構成を取得できます。
- 授業資料(KULMS 画面上の「リソース」)を一覧表示、またはコース別ディレクトリにダウンロードできます。
- 課題を全コース横断、またはコース指定で取得できます。
- 課題をステータスや締切日で絞り込めます。
- お知らせを全コース横断、またはコース指定で取得できます。
- お知らせを日数、件数、作成日で絞り込めます。
- カレンダーを全コース横断、またはコース指定で取得できます。
- Direct API の任意パスを直接呼び出せます。
- Pydantic v2 モデルとしてレスポンスを扱えます。
用語
Sakai の API では授業が site、授業資料が content と呼ばれます。このライブラリと CLI では、KULMS の画面上で見慣れた言葉に合わせて主に次の名前を使います。
| Sakai Direct API | kulms での名前 | 意味 |
|---|---|---|
site |
course |
授業、コース |
content |
resources |
授業資料、KULMS 上の「リソース」 |
assignment |
assignments |
課題 |
announcement |
announcements |
お知らせ |
calendar |
calendar |
カレンダー |
CLI の引数は COURSE_ID と表示されます。これは kulms courses で表示されるコース ID です。
インストール
Python 3.12 以上を前提にしています。PyPI からインストールする場合は次の通りです。
python -m pip install kulms
CLI として普段使いする場合は、アプリケーションとして分離して入れられる uv tool install も便利です。
uv tool install kulms
初回だけ、uv の tool 用ディレクトリを PATH に入れます。すでに設定済みなら不要です。
uv tool update-shell
PowerShell を開き直したあと、どこからでも次のように実行できます。
kulms --help
kulms auth status
kulms courses
pipx を使う場合は次の通りです。
pipx install kulms
ライブラリとして使う場合も pip install kulms で同じパッケージを使います。kulms コマンドを配布しているため、CLI 依存関係は通常依存に含めています。
開発環境を用意する場合は、リポジトリを clone して次を実行します。
uv sync --group dev
開発中の作業ツリーを CLI として入れる場合は次の通りです。
uv tool install --editable .
アンインストールする場合は次の通りです。
uv tool uninstall kulms
CLIの使い方
初期設定
CLIを使うにはまず最初にログインします。
kulms auth login
ログイン時に入力するものは次の通りです。
| 入力 | 保存先 | 備考 |
|---|---|---|
| Username | keyring | 京都大学 ECS-ID などです。 |
| Password | keyring | getpass.getpass() で非表示入力します。 |
| TOTP secret | keyring | 保存を選んだ場合だけ保存します。 |
| One-time password | 保存しません | TOTP secret を保存しない場合に入力します。 |
TOTP シークレットは 京大の多要素認証マニュアル に従って認証アプリを登録する際の QR に埋め込まれた otpauth://totp/...?secret=XXXX&... の secret パラメータです。登録後は QR が再表示されないので、登録画面で控えておくか、一度アプリを解除して再登録してください。
TOTP シークレットを保存すると、kulms auth refresh 時にワンタイムパスワードを手で入力しなくてよくなります。一方で、CLI が実質的に認証アプリ相当の情報を持つことになります。共有 PC や管理外の端末では保存しない方が安全です。
認証とセッション
CLI は資格情報とセッションを分けて扱います。
| 種類 | 保存場所 | 削除コマンド |
|---|---|---|
| ユーザー名 | keyring | kulms auth forget |
| パスワード | keyring | kulms auth forget |
| TOTP シークレット | keyring | kulms auth forget |
| セッション Cookie | ユーザーキャッシュディレクトリ | kulms auth logout または kulms auth forget |
セッション Cookie の実際のパスは kulms auth status で確認できます。Windows では通常 %LOCALAPPDATA% 配下に保存されます。
セッション Cookie はログイン済みセッションとして扱える情報です。保存時は原子的に書き込み、可能な環境では所有者だけが読める権限にしますが、共有端末では kulms auth logout または kulms auth forget で削除してください。
通常の CLI コマンドは、セッションが切れても裏で勝手に再ログインしません。セッション切れになった場合は明示的に次を実行します。
kulms auth refresh
完全にログインし直す場合は次を実行します。
kulms auth login
セッションだけ消す場合は次の通りです。keyring の資格情報は残ります。
kulms auth logout
資格情報とセッションを両方消す場合は次の通りです。
kulms auth forget
現在の状態は次で確認できます。
kulms auth status
プロファイル
複数アカウントや検証環境を分けたい場合は --profile を使います。
kulms --profile main auth login
kulms --profile main courses
プロファイルごとに keyring のサービス名とセッション Cookie ファイルが分かれます。デフォルトのプロファイル名は default です。
コース一覧
kulms courses
コース ID、コース名、種別を表示します。以降の COURSE_ID にはここに表示される ID を使います。
JSON で取得する場合は次の通りです。
kulms courses --json
コース詳細
kulms course show COURSE_ID
コース名、コース ID、説明があれば説明を表示します。
コースのタブ一覧
kulms course tabs COURSE_ID
KULMS の授業ページ左側に出る「概要」「カレンダー」「お知らせ」「授業資料(リソース)」「課題」「小テスト」などのタブと、その裏側の Sakai tool ID を表示します。
例として、小テストは sakai.samigo として見えることがあります。小テスト API 自体は現時点の高水準ラッパーでは未対応ですが、Direct API ドキュメントには sam_pub、sam_core、sam_item などの関連エンティティがあります。
授業資料、リソースの一覧
kulms resources COURSE_ID
KULMS 上で「リソース」と表示される授業資料を一覧表示します。フォルダは folder、ファイルは file として表示します。
授業資料、リソースのダウンロード
kulms resources COURSE_ID --download
デフォルトではカレントディレクトリの KULMS 配下に次の構造で保存します。
KULMS/
Course Title/
Folder Name/
file.pdf
保存先を変える場合は --dest を使います。
kulms resources COURSE_ID --download --dest .\downloads
実際に保存せず、保存予定だけ確認する場合は --dry-run を使います。
kulms resources COURSE_ID --download --dry-run
既存ファイルはデフォルトでスキップします。上書きする場合は --overwrite を使います。
kulms resources COURSE_ID --download --overwrite
デフォルトでは https://lms.gakusei.kyoto-u.ac.jp/access/content/ 配下のファイルだけをダウンロードします。リソースに外部リンクが含まれている場合はスキップします。外部 URL も取得したい場合だけ、明示的に --allow-external を付けてください。
kulms resources COURSE_ID --download --allow-external
1ファイルあたりの最大サイズはデフォルトで 512 MiB です。変更する場合は --max-bytes を使います。
kulms resources COURSE_ID --download --max-bytes 104857600
ダウンロード結果のステータスは主に次の値です。
| ステータス | 意味 |
|---|---|
downloaded |
ダウンロードしました。 |
skipped |
既存ファイルがある、または外部 URL のためスキップしました。 |
planned |
--dry-run による保存予定です。 |
failed |
HTTP エラーなどで失敗しました。 |
ファイル名やフォルダ名に Windows で使えない文字が含まれる場合は _ に置き換えます。
課題一覧
全コース横断で課題を表示します。
kulms assignments
コースを指定する場合は次の通りです。
kulms assignments COURSE_ID
ステータスで絞り込む場合は --status を使います。
kulms assignments --status OPEN
複数ステータスを指定する場合は --status を複数回指定します。
kulms assignments --status OPEN --status DUE
締切日で絞り込む場合は --from と --to を使います。日付範囲は両端を含みます。
kulms assignments --from 2026-04-20 --to 2026-04-30
ステータスと日付は同時に指定できます。
kulms assignments --status OPEN --from 2026-04-20 --to 2026-05-10
お知らせ一覧
全コース横断でお知らせを表示します。
kulms announcements
コースを指定する場合は次の通りです。
kulms announcements COURSE_ID
最近の日数で絞る場合は --days を使います。
kulms announcements --days 7
最大件数を指定する場合は --limit を使います。
kulms announcements --limit 20
作成日で絞り込む場合は --from と --to を使います。
kulms announcements --from 2026-04-01 --to 2026-04-30
カレンダー
全コース横断でカレンダーイベントを表示します。
kulms calendar
コースを指定する場合は次の通りです。
kulms calendar COURSE_ID
日付範囲を指定する場合は --from と --to を使います。
kulms calendar --from 2026-04-01 --to 2026-04-30
Sakai Direct API のパラメータ名に合わせて --first-date と --last-date も使えます。
kulms calendar --first-date 2026-04-01 --last-date 2026-04-30
ダッシュボード
課題、お知らせ、カレンダーをまとめて表示します。
kulms dashboard
現時点では簡易表示です。詳細な絞り込みや機械処理には assignments、announcements、calendar の各コマンドを使う方が向いています。
Direct API を直接呼ぶ
高水準ラッパーがまだないエンドポイントは kulms direct で呼べます。
kulms direct get site
kulms direct get /direct/site.json
kulms direct get /direct/user/current.json
JSON として表示できるレスポンスは自動的に整形されます。生レスポンスを見たい場合は --raw を使います。
kulms direct get /direct/site.json --raw
/direct/describe を見る場合は次の通りです。
kulms direct describe
特定 prefix の describe を見る場合は次の通りです。
kulms direct describe assignment
kulms direct describe content
JSON 出力
多くの CLI コマンドは --json をサポートしています。
kulms assignments --status OPEN --json
kulms resources COURSE_ID --download --dry-run --json
JSON 出力では Pydantic モデルを model_dump(mode="json", by_alias=True) 相当で出力します。Sakai の camelCase フィールド名をできるだけ保った JSON になります。
ライブラリの使い方
以下に最小例を示します。
from kulms import KULMSClient
client = KULMSClient.from_credentials(
username="USERNAME",
password="PASSWORD",
totp_secret="TOTP_SECRET",
)
session = client.sessions.current()
courses = client.courses.list()
assignments = client.assignments.list()
KULMSClient はコンテキストマネージャとしても使えます。
from kulms import KULMSClient
with KULMSClient.from_credentials(username, password, totp_secret=totp_secret) as client:
for course in client.courses.list():
print(course.id, course.title)
ワンタイムパスワードを直接渡す場合は次の通りです。
client = KULMSClient.from_credentials(
username,
password,
onetime_password="123456",
)
必要になったタイミングで OTP を取得したい場合は otp_callback を渡せます。
client = KULMSClient.from_credentials(
username,
password,
otp_callback=lambda: input("OTP: "),
)
ライブラリでのセッション保存
ライブラリ側でも JsonFileSessionStore を使って Cookie を保存できます。
from pathlib import Path
from kulms import AuthExpiredError, KULMSClient
from kulms.session import JsonFileSessionStore
store = JsonFileSessionStore(Path("kulms.cookies.json"))
client = KULMSClient.from_credentials(
username,
password,
totp_secret=totp_secret,
session_store=store,
load_session=True,
trust_loaded_session=True,
)
try:
client.sessions.current()
except AuthExpiredError:
client = KULMSClient.from_credentials(
username,
password,
totp_secret=totp_secret,
session_store=store,
load_session=False,
)
client.sessions.current()
client.save_session()
load_session=True は保存済み Cookie を読み込みます。trust_loaded_session=True の場合、読み込んだ Cookie があると kuauth の内部ログイン状態を「準備済み」として扱い、不要な SSO フローを避けます。
保存済み Cookie は期限切れのものを読み飛ばします。セッションがサーバー側で無効になっている場合は API 呼び出し時に AuthExpiredError が発生します。
高水準 API
client.courses
コース、Sakai の site を扱います。
| メソッド | 内容 |
|---|---|
list(limit=100, offset=0) |
コース一覧を取得します。Sakai の _limit と _start に対応します。 |
iter(page_size=100) |
ページングしながらコースを順に yield します。 |
get(site_id, include_groups=False) |
コース詳細を取得します。 |
tabs(site_id, props=False, config=False) |
コースのページ、タブ、ツール一覧を取得します。 |
exists(site_id) |
コースが存在するか確認します。 |
例です。
courses = client.courses.list(limit=50)
for course in client.courses.iter(page_size=100):
print(course.id, course.title)
tabs = client.courses.tabs("COURSE_ID")
client.resources
授業資料、KULMS 上の「リソース」を扱います。Sakai Direct API では content です。
| メソッド | 内容 |
|---|---|
list(site_id) |
指定コースのリソース一覧を取得します。 |
list_my() |
自分に関連するリソース一覧を取得します。 |
download(site_id, dest="KULMS", overwrite=False, dry_run=False, allow_external=False, max_file_size=536870912) |
指定コースのファイルをダウンロードします。 |
download() はフォルダ、つまり collection を保存対象から除外し、ファイルだけを保存します。保存先は dest / course title / resource path です。デフォルトでは KULMS の /access/content/ 配下だけを取得し、外部 URL はスキップします。
items = client.resources.list("COURSE_ID")
results = client.resources.download(
"COURSE_ID",
dest="KULMS",
dry_run=True,
)
client.assignments
課題を扱います。
| メソッド | 内容 |
|---|---|
list(site_id=None, limit=None, offset=None, status=None, from_date=None, to_date=None) |
課題一覧を取得します。 |
get(assignment_id) |
課題 ID で課題を取得します。 |
site_id=None の場合は /direct/assignment/my を使い、全コース横断の課題を取得します。site_id を指定した場合は /direct/assignment/site/{site_id} を使います。
status は文字列または文字列リストを受け取ります。比較は大文字小文字を無視します。
from_date と to_date は締切日での絞り込みです。文字列、date、datetime、epoch 秒、epoch ミリ秒を扱えます。日付範囲は両端を含みます。
open_assignments = client.assignments.list(status="OPEN")
upcoming = client.assignments.list(
status=["OPEN", "DUE"],
from_date="2026-04-20",
to_date="2026-05-10",
)
course_assignments = client.assignments.list("COURSE_ID")
client.announcements
お知らせを扱います。
| メソッド | 内容 |
|---|---|
list(site_id=None, days=None, limit=None, from_date=None, to_date=None) |
お知らせ一覧を取得します。 |
motd(days=None, limit=None) |
今日のお知らせを取得します。 |
site_id=None の場合は /direct/announcement/user を使い、全コース横断のお知らせを取得します。site_id を指定した場合は /direct/announcement/site/{site_id} を使います。
days は Sakai の d パラメータ、limit は n パラメータに対応します。from_date と to_date は createdOn に対するローカル日付での絞り込みです。
announcements = client.announcements.list(limit=20)
recent = client.announcements.list(days=7)
course_news = client.announcements.list("COURSE_ID")
client.calendar
カレンダーイベントを扱います。
| メソッド | 内容 |
|---|---|
list(site_id=None, first_date=None, last_date=None) |
カレンダーイベント一覧を取得します。 |
site_id=None の場合は /direct/calendar/my を使い、全コース横断のイベントを取得します。site_id を指定した場合は /direct/calendar/site/{site_id} を使います。
events = client.calendar.list(first_date="2026-04-01", last_date="2026-04-30")
course_events = client.calendar.list("COURSE_ID")
client.users
現在のユーザー情報を扱います。
| メソッド | 内容 |
|---|---|
current() |
/direct/user/current を取得します。 |
user = client.users.current()
print(user.eid, user.display_name)
client.sessions
現在の Sakai セッション情報を扱います。
| メソッド | 内容 |
|---|---|
current() |
/direct/session/current を取得します。 |
session = client.sessions.current()
print(session.user_eid, session.active)
client.direct
未ラップの Sakai Direct API を呼ぶ低水準クライアントです。
| メソッド | 内容 |
|---|---|
request(method, path_or_url, 追加キーワード引数) |
kuauth の KULMS サービス経由で HTTP リクエストを送ります。 |
get_json(path_or_url, params=None, ensure_json_suffix=True) |
GET して JSON として返します。 |
post_json(path_or_url, data=None, json_data=None, params=None, ensure_json_suffix=True) |
POST して JSON として返します。 |
パスは次のように正規化されます。
| 入力例 | 実際の扱い |
|---|---|
site |
/direct/site.json |
/site |
/direct/site.json |
/direct/site |
/direct/site.json |
/direct/site.json |
/direct/site.json |
/access/content/... |
/access/content/... |
https://... |
絶対 URL として扱います。 |
request() は /access や /portal も保持するため、リソースファイルのダウンロードに使えます。
raw_sites = client.direct.get_json("site")
assignment_doc = client.direct.get_json("/direct/assignment/my")
response = client.direct.request("GET", "/access/content/group/example/file.pdf")
ライブラリ内のモデル
モデルは Pydantic v2 の BaseModel を継承しています。extra="allow" なので、現在モデルに定義していない Sakai の追加フィールドも落とさず保持します。populate_by_name=True なので、Python 側の snake_case 名と Sakai 側の alias 名の両方を受け取れます。
| モデル | 主なフィールド |
|---|---|
Course |
id, title, type, description, entity_id, entity_title, entity_url |
CourseTab |
id, title, site_id, url, tools |
CourseTool |
id, title, tool_id, placement_id, site_id, page_id, url |
ResourceItem |
id, title, name, type, url, path, container, size, children |
DownloadResult |
source_url, path, status, bytes, message |
Assignment |
id, title, context, status, instructions, due_time, due_time_string, open_time, close_time |
Announcement |
id, announcement_id, title, body, site_id, site_title, created_on, created_by_display_name |
CalendarEvent |
event_id, title, description, site_id, site_name, first_time, duration, type |
SessionInfo |
id, active, user_id, user_eid, creation_time, current_time, last_accessed_time, max_inactive_interval |
User |
id, eid, display_id, display_name, email, first_name, last_name, type |
ResourceItem には便利なプロパティがあります。
| プロパティ | 内容 |
|---|---|
display_name |
title, name, id の順に表示名を返します。 |
download_url |
webLinkUrl, downloadUrl, contentUrl, url, entityURL などからダウンロード URL を推定します。 |
is_collection |
フォルダ相当の collection かどうかを返します。 |
ライブラリ内の例外
公開されている例外は次の通りです。
| 例外 | 意味 |
|---|---|
KULMSError |
このパッケージの基底例外です。 |
AuthExpiredError |
セッション切れ、未認可、認証ページへのリダイレクトなどで発生します。 |
APIError |
JSON でないレスポンス、HTTP エラー、不正 JSON などで発生します。 |
NotFoundError |
HTTP 404 の場合に発生します。APIError のサブクラスです。 |
CLI では AuthExpiredError を検出すると、kulms auth login を促して終了コード 2 で終了します。その他の KULMSError は終了コード 1 です。
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kulms-0.1.0.tar.gz.
File metadata
- Download URL: kulms-0.1.0.tar.gz
- Upload date:
- Size: 58.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5bfa927e59fbd79bebd0fea58b302d067ca5ad2701ad9a30902cb013b9645820
|
|
| MD5 |
d75ed51f0091029a21dc0aee77da9f62
|
|
| BLAKE2b-256 |
5124b1fc8196fc5939984ff6874aa4352d954dea4f90a08616ceff1f00498188
|
File details
Details for the file kulms-0.1.0-py3-none-any.whl.
File metadata
- Download URL: kulms-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4789555cd7f4e26028082b6ea912a90efe222f8587dc5586bfba7d646afb0fa5
|
|
| MD5 |
1bdde073d8b96b615d22c824a54acc76
|
|
| BLAKE2b-256 |
0291c7cdf40221e80b1e7552c12e384a2106ba29278947e1aaea92b1ddd08e48
|