Metadata-Version: 2.3
Name: meetschedule-sdk
Version: 1.0
Summary: Python SDK for the Meet Schedule Open API — 面向第三方的课程表开放接口
Author: Bail
Author-email: Bail <2915289604@qq.com>
Requires-Dist: httpx>=0.28.1
Requires-Python: >=3.12
Description-Content-Type: text/markdown

# Meet Schedule SDK — Python

[Meet 课程表 开放 API](https://api.meetschedule.top) 的 Python SDK。

## 安装

```bash
uv add meetschedule-sdk
# 或
pip install meetschedule-sdk
```

## 快速开始

```python
from meetschedule_sdk import MeetSchedule

client = MeetSchedule(api_key="msk_live_xxxxxxxxxxxxxxxxxxxx")

# 列出所有课表
for s in client.schedules.get_all():
    print(f"[{s.id}] {s.name} ({s.course_count} 门课)")

# 获取课表完整数据
bundle = client.schedules.get_full("sch_xxx")
for c in bundle.courses:
    print(f"  {c.name} — {len(c.meetings)} 条上课安排")

# 创建事件
event = client.events.create(
    schedule_id="sch_xxx",
    type="exam",
    title="期中考试",
    time_mode="range",
    start_at="2025-11-10T08:00:00Z",
    end_at="2025-11-10T10:00:00Z",
)
print(f"已创建事件 {event.id}")

# 新建待办
task = client.tasks.create(title="完成实验报告", group="作业")
client.tasks.update(task.id, done=True)
```

## Async 用法

```python
import asyncio
from meetschedule_sdk import AsyncMeetSchedule

async def main():
    async with AsyncMeetSchedule(api_key="msk_live_xxxxxxxxxxxxxxxxxxxx") as client:
        # 所有方法与 sync 版本同名，只需加 await
        schedules = await client.schedules.get_all()
        for s in schedules:
            print(f"[{s.id}] {s.name}")

        # 获取课表完整数据
        bundle = await client.schedules.get_full("sch_xxx")
        for c in bundle.courses:
            print(f"  {c.name} — {len(c.meetings)} 条上课安排")

        # 批量并行操作
        results = await asyncio.gather(
            client.tasks.get_all(),
            client.events.list("sch_xxx", type="exam"),
        )
        tasks, exams = results

asyncio.run(main())
```

## API 概览

| 客户端属性 | API 端点 | 所需 Scope |
|---|---|---|
| `client.schedules` | `/open/v1/schedules` | `schedule:read` / `schedule:write` |
| `client.courses` | `/open/v1/schedules/{id}/courses` | `entities:read` / `entities:write` |
| `client.events` | `/open/v1/schedules/{id}/events` | `entities:read` / `entities:write` |
| `client.adjustments` | `/open/v1/schedules/{id}/adjustments` | `entities:read` / `entities:write` |
| `client.tasks` | `/open/v1/tasks` | `entities:read` / `entities:write` |

### Schedules

| 方法 | 说明 |
|---|---|
| `client.schedules.get_all()` | 列出所有课表 |
| `client.schedules.get(schedule_id)` | 获取单个课表信息 |
| `client.schedules.create(name, start_date, ...)` | 新建课表 |
| `client.schedules.update(schedule_id, ...)` | 更新课表设置 |
| `client.schedules.delete(schedule_id)` | 删除课表（不可恢复） |
| `client.schedules.get_full(schedule_id)` | 拉取课表完整数据（含课程/事件/调停课） |

### Courses

| 方法 | 说明 |
|---|---|
| `client.courses.get_all(schedule_id)` | 列出课表下的所有课程 |
| `client.courses.create(schedule_id, name, meetings, ...)` | 新建课程 |
| `client.courses.update(course_id, ...)` | 更新课程 |
| `client.courses.delete(course_id)` | 删除课程 |

### Events

| 方法 | 说明 |
|---|---|
| `client.events.get_all(schedule_id, type=..., from_time=..., to=...)` | 列出事件 |
| `client.events.create(schedule_id, type, title, time_mode, ...)` | 新建事件 |
| `client.events.update(event_id, ...)` | 更新事件 |
| `client.events.delete(event_id)` | 删除事件 |

### Adjustments（调停课）

| 方法 | 说明 |
|---|---|
| `client.adjustments.get_all(schedule_id)` | 列出调停课 |
| `client.adjustments.create(schedule_id, type, ...)` | 新建调停课 |
| `client.adjustments.delete(adjustment_id)` | 删除调停课 |

### Tasks（待办）

| 方法 | 说明 |
|---|---|
| `client.tasks.get_all()` | 列出所有待办 |
| `client.tasks.create(title, ...)` | 新建待办 |
| `client.tasks.update(task_id, ...)` | 更新待办 |
| `client.tasks.delete(task_id)` | 删除待办 |

## 错误处理

所有 API 错误都会抛出 `ApiException` 的子类：

```python
from meetschedule_sdk import (
    MeetSchedule,
    UnauthorizedError,
    ForbiddenError,
    NotFoundError,
    UnprocessableEntityError,
    TooManyRequestsError,
    NetworkError,
)

client = MeetSchedule(api_key="...")

try:
    schedule = client.schedules.get("sch_xxx")
except UnauthorizedError:
    print("API Key 无效")
except ForbiddenError:
    print("API Key 缺少必要的 scope")
except NotFoundError:
    print("课表不存在")
except TooManyRequestsError:
    print("触发限流，请稍后重试")
except NetworkError:
    print("网络连接失败")
```

## 数据模型

SDK 使用 Python `dataclass` 表示所有数据模型。返回的数据会自动反序列化为对应的模型实例。

```python
from meetschedule_sdk.models import (
    Schedule, ScheduleBundle,
    Course, CourseInput, MeetingInput,
    Event, EventInput,
    Adjustment, AdjustmentInput,
    Task, TaskInput,
    DayOfWeek, Category, EventType, TimeMode, AdjustmentType,
)
```

创建/更新时既可以传模型实例，也可以用字典风格的 `**kwargs`：

```python
# 方式一：传模型
from meetschedule_sdk.models import MeetingInput
course = client.courses.create(
    schedule_id="sch_xxx",
    name="高等数学（下）",
    meetings=[
        MeetingInput(day_of_week=1, start_period=3, end_period=4, weeks=[1,3,5]),
    ],
)

# 方式二：传 dict
course = client.courses.create(
    schedule_id="sch_xxx",
    name="高等数学（下）",
    meetings=[{"day_of_week": 1, "start_period": 3, "end_period": 4, "weeks": [1, 3, 5]}],
)
```

## 许可证

GPLv3
