Python client and CLI for KULMS/Sakai Direct API
Project description
kulms
kulms は、京都大学の KULMS を扱うための Python ライブラリ兼 CLI です。
Sakai Direct API をそのまま触らなくても、KULMS で見慣れた単位でコース、リソース、課題、お知らせ、カレンダーを扱えます。
- CLI として使って、課題確認や授業資料のダウンロードをしたい人向け。
- Python ライブラリとして使って、KULMS をスクリプトから触りたい人向け。
- 高水準 API がまだない箇所は
kulms directやclient.directで直接叩けます(Sakai APIにはないKULMS上でのWebページも取得可能です)。
インストール
Python 3.12 以上が必要です。
CLI として使うなら:
uv tool install kulms
uv tool update-shell
または:
pipx install kulms
ライブラリとして使うなら:
python -m pip install kulms
最初に必要なもの
最初に用意するものは次の 3 つです。
- ECS-ID などのユーザー名
- パスワード
- 現在有効なワンタイムパスワード、または TOTP シークレット
TOTP シークレットは、京大の多要素認証マニュアル に従って認証アプリを登録する際の QR コードに埋め込まれた otpauth://totp/...?secret=XXXX&... の secret パラメータです。
登録後は QR が再表示されないことが多いので、登録画面で控えておくのが安全です。すでに控えていない場合は、一度アプリを解除して再登録が必要になることがあります。
これを登録時に控えていない場合、あとから使う方法は次のどちらかになります。
- CLI では、ログインや更新のたびにワンタイムパスワードを入力する
- ライブラリでは、
onetime_password=...またはotp_callback=...を使う
毎回 OTP を手入力したくないなら、多要素認証を再登録して TOTP シークレットを控え直す必要があります。
CLI として使う
CLIを使う際にまずログインが必要です。
kulms auth login
kulms auth login では TOTP シークレットを keyring に保存するか聞かれます。
- 保存する場合: 一度だけ TOTP シークレットを入力します。以後
kulms auth refreshで OTP の手入力なしにセッション更新できます。 - 保存しない場合: その場でワンタイムパスワードを入力します。TOTP シークレットは保存しません。
ログイン後は、まず次のコマンドを使うことが多いです。
kulms courses # 履修中のコース一覧を見る
kulms assignments --status OPEN # 未対応の課題を見る
kulms announcements --days 7 # 直近 7 日のお知らせを見る
kulms calendar --from 2026-04-01 --to 2026-04-30 # 指定期間の予定を見る
授業資料を見たい、落としたい場合は kulms courses で COURSE_ID を確認してから使います。
kulms resources COURSE_ID # 授業のリソース一覧を見る
kulms resources COURSE_ID --download # 授業のリソースをダウンロードする
認証まわりでよく使うコマンド:
kulms auth status # 保存済み資格情報とセッション状態を確認する
kulms auth profiles # 作成済みプロファイル一覧を見る
kulms auth refresh # セッションを更新する
kulms auth logout # セッションだけ削除する
kulms auth forget # 資格情報とセッションを両方削除し、このプロファイルを忘れる
アカウントを分けたい場合は --profile を付けます。
kulms --profile main auth login # profile=main でログインする
kulms --profile main courses # profile=main のコース一覧を見る
作成済みのプロファイル名を忘れた場合は、次のコマンドで確認できます。
kulms auth profiles # 作成済みプロファイル一覧を見る
高水準コマンドで足りない場合は、kulms direct で Direct API を直接呼べます。
CLI では、次のどちらも使えます。
- KULMS のドメイン以降のパスを渡す
- KULMS の完全な URL をそのまま渡す
site のような短い名前を書くと /direct/site.json として扱われます。
kulms direct get site # 短い名前を渡す
kulms direct get /direct/user/current.json # ドメイン以降のパスを渡す
kulms direct get https://lms.gakusei.kyoto-u.ac.jp/direct/user/current.json # 完全な URL を渡す
kulms direct get /portal --raw # HTML をそのまま見る
ライブラリとして使う
最短は KULMSClient.from_credentials() です。
TOTP シークレットを持っている場合:
from kulms import KULMSClient
with KULMSClient.from_credentials(
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
totp_secret="YOUR_TOTP_SECRET", # MFA 登録時に控えた TOTP シークレット
) as client:
for course in client.courses.list(): # コース一覧を取得する
print(course.id, course.title)
TOTP シークレットを保存したくない、または持っていない場合は、今この瞬間に有効な OTP を直接渡す方法があります。
from kulms import KULMSClient
with KULMSClient.from_credentials(
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
onetime_password="123456", # 現在有効なワンタイムパスワードを直接渡す
) as client:
assignments = client.assignments.list(status=["OPEN"]) # 未対応の課題を取る
for item in assignments:
print(item.title, item.status)
対話的に OTP を入力させたい場合は otp_callback も使えます。
from kulms import KULMSClient
with KULMSClient.from_credentials(
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
otp_callback=lambda: input("OTP: "), # 必要になった時点で OTP を入力する
) as client:
assignments = client.assignments.list(status=["OPEN"])
for item in assignments:
print(item.title, item.status)
高水準 API:
client.coursesclient.resourcesclient.assignmentsclient.announcementsclient.calendarclient.usersclient.sessionsclient.direct
例:
items = client.resources.list("COURSE_ID")
news = client.announcements.list(limit=10)
events = client.calendar.list(first_date="2026-04-01", last_date="2026-04-30")
raw = client.direct.get_json("site")
高水準 API で足りない場合は、client.direct で Direct API を直接呼べます。
client.direct.get_json() は JSON を返すエンドポイント向けです。
普通の HTML ページを取りたい場合は client.direct.request("GET", ...) を使います。
client.direct.request() は /direct/...、/access/...、/portal/...、絶対 URL を受け付けます。
from kulms import KULMSClient
with KULMSClient.from_credentials(
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
otp_callback=lambda: input("OTP: "),
) as client:
print(client.direct.get_json("site")) # JSON を返す Direct API を呼ぶ
print(client.direct.get_json("/direct/user/current.json")) # JSON を返すパスを渡す
response = client.direct.request("GET", "/portal") # 普通の HTML ページを取る
print(response.text)
セキュリティ
kulms は資格情報とセッションを分けて扱います。
- ユーザー名、パスワード、TOTP シークレットは
keyringに保存されます - セッション Cookie はユーザーキャッシュディレクトリに保存されます
kulms auth statusで保存状態とセッションファイルの場所を確認できます
注意点:
- TOTP シークレットを保存すると便利ですが、利用する端末が実質的に「パスワード + 二要素」の両方を持つことになります
- 共有 PC や管理されていない端末では、TOTP シークレットを保存しない方が安全です
- 少しでもリスクを下げたいなら、TOTP シークレットは保存せず、ログインや更新ごとに OTP を入力してください
kulms auth logoutはセッションだけ消しますkulms auth forgetはセッションと保存済み資格情報を両方消します
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.3.tar.gz.
File metadata
- Download URL: kulms-0.1.3.tar.gz
- Upload date:
- Size: 55.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ff4ef0c7f8ee0ecba9533a414eb8193e39d41ff3a461cdf1de087ce86a90c76
|
|
| MD5 |
67e9aaf4256e8c604f764d1e76399f6e
|
|
| BLAKE2b-256 |
1459b67199a53ba510e20631266cc0cc4baf22886709d021e59adb502885e645
|
File details
Details for the file kulms-0.1.3-py3-none-any.whl.
File metadata
- Download URL: kulms-0.1.3-py3-none-any.whl
- Upload date:
- Size: 27.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a89ba65cddb58142f5fa3e75ef208c3dbd240ede5bd55e78b0c6764ae2fb7a0d
|
|
| MD5 |
af611be8a32b6c4721d8e330f74628b2
|
|
| BLAKE2b-256 |
bd812aa1914bf73fb19ae3113ec2351783bd66d4d4849eaa3265e93781ebca3f
|