客户端¶
同步客户端¶
QBClient
¶
QBClient(
base_url: str,
*,
access_token: str | None = None,
timeout: float = 30.0,
check_version: bool = True
)
Bases: AuthMixin, QuestionsMixin, PapersMixin
同步题库客户端,面向 bot 账号。
Bot 账号使用管理员签发的 access token 认证,无需用户名密码登录。
用法::
client = QBClient("http://localhost:8080", access_token="bot-token-xxx")
questions = client.list_questions(category="T")
client.close()
或作为上下文管理器::
with QBClient("http://localhost:8080", access_token="bot-token-xxx") as c:
...
Args:
base_url: API 服务地址,如 http://localhost:8080。
access_token: 管理员签发的 bot access token。
timeout: HTTP 请求超时时间(秒)。
check_version: 是否在首次连接时校验后端版本兼容性。
search_users
¶
按关键词搜索用户(用于审阅人分配)。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
q
|
str
|
搜索关键词,匹配 username / display_name。 |
必需 |
limit
|
int | None
|
每页数量 (1-100)。 |
None
|
offset
|
int | None
|
偏移量。 |
None
|
list_questions
¶
list_questions(
*,
paper_id: str | None = None,
category: str | None = None,
tag: str | None = None,
author: str | None = None,
reviewer: str | None = None,
assigned_reviewer_id: str | None = None,
score_min: int | None = None,
score_max: int | None = None,
difficulty_tag: str | None = None,
difficulty_min: int | None = None,
difficulty_max: int | None = None,
q: str | None = None,
created_after: str | None = None,
created_before: str | None = None,
updated_after: str | None = None,
updated_before: str | None = None,
limit: int | None = None,
offset: int | None = None
) -> PaginatedResponse[QuestionSummary]
分页查询题目。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
paper_id
|
str | None
|
按所属试卷过滤。 |
None
|
category
|
str | None
|
按分类过滤 ( |
None
|
tag
|
str | None
|
按标签过滤。 |
None
|
author
|
str | None
|
按命题人过滤(支持逗号分隔多值)。 |
None
|
reviewer
|
str | None
|
按审核人过滤(支持逗号分隔多值)。 |
None
|
assigned_reviewer_id
|
str | None
|
按分配的审阅人 UUID 过滤。 |
None
|
score_min
|
int | None
|
分值下限。 |
None
|
score_max
|
int | None
|
分值上限。 |
None
|
difficulty_tag
|
str | None
|
难度 tag,如 |
None
|
difficulty_min
|
int | None
|
难度下限 (1-10)。 |
None
|
difficulty_max
|
int | None
|
难度上限 (1-10)。 |
None
|
q
|
str | None
|
关键词,模糊匹配 description。 |
None
|
created_after
|
str | None
|
创建时间下限 (ISO 8601)。 |
None
|
created_before
|
str | None
|
创建时间上限 (ISO 8601)。 |
None
|
updated_after
|
str | None
|
更新时间下限 (ISO 8601)。 |
None
|
updated_before
|
str | None
|
更新时间上限 (ISO 8601)。 |
None
|
limit
|
int | None
|
每页数量 (1-100),默认 20。 |
None
|
offset
|
int | None
|
偏移量。 |
None
|
get_question
¶
get_question(question_id: str) -> QuestionDetail
获取单个题目完整详情。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
question_id
|
str
|
题目 UUID。 |
必需 |
create_question
¶
create_question(
file: str | Path | IO[bytes],
*,
description: str,
category: str | None = None,
tags: list[str] | None = None
) -> QuestionCreateResult
上传新题目(zip 包)。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
file
|
str | Path | IO[bytes]
|
zip 文件路径或已打开的二进制文件对象。 |
必需 |
description
|
str
|
题目描述。 |
必需 |
category
|
str | None
|
分类 ( |
None
|
tags
|
list[str] | None
|
标签列表。 |
None
|
update_question_description
¶
update_question_description(
question_id: str, description: str
) -> QuestionDetail
更新题目描述。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
question_id
|
str
|
题目 UUID。 |
必需 |
description
|
str
|
题目描述。 |
必需 |
update_question_category
¶
update_question_category(
question_id: str, category: str
) -> QuestionDetail
更新题目分类。
update_question_tags
¶
update_question_tags(
question_id: str, tags: list[str]
) -> QuestionDetail
整体替换题目标签。
update_question_status
¶
update_question_status(
question_id: str, status: str
) -> QuestionDetail
更新题目状态。
update_question_author
¶
update_question_author(
question_id: str, author: str
) -> QuestionDetail
更新题目命题人。
update_question_reviewer_names
¶
update_question_reviewer_names(
question_id: str, reviewers: list[str]
) -> QuestionDetail
整体替换题目审题人显示名列表。
create_question_difficulty
¶
create_question_difficulty(
question_id: str,
algorithm_tag: str,
score: int,
*,
notes: str | None = None
) -> QuestionDetail
创建题目难度条目。
update_question_difficulty
¶
update_question_difficulty(
question_id: str,
algorithm_tag: str,
score: int,
*,
notes: str | None = None
) -> QuestionDetail
更新题目难度条目。
delete_question_difficulty
¶
delete_question_difficulty(
question_id: str, algorithm_tag: str
) -> QuestionDetail
删除题目难度条目。
replace_question_file
¶
replace_question_file(
question_id: str, file: str | Path | IO[bytes]
) -> QuestionFileReplaceResult
替换题目的 zip 文件内容,不修改元数据。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
question_id
|
str
|
题目 UUID。 |
必需 |
file
|
str | Path | IO[bytes]
|
新的 zip 文件路径或二进制文件对象。 |
必需 |
download_question_bundle
¶
批量打包下载题目原始文件到本地。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
question_ids
|
list[str]
|
题目 UUID 列表。 |
必需 |
save_to
|
str | Path
|
本地保存路径。 |
必需 |
返回:
| 类型 | 描述 |
|---|---|
Path
|
保存的文件路径。 |
assign_reviewer
¶
assign_reviewer(
question_id: str, reviewer_id: str
) -> ReviewersResponse
分配审阅人到题目。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
question_id
|
str
|
题目 UUID。 |
必需 |
reviewer_id
|
str
|
要分配的用户 UUID(必须为 |
必需 |
remove_reviewer
¶
remove_reviewer(
question_id: str, reviewer_id: str
) -> ReviewersResponse
移除题目的审阅人。
list_papers
¶
list_papers(
*,
question_id: str | None = None,
category: str | None = None,
tag: str | None = None,
q: str | None = None,
created_after: str | None = None,
created_before: str | None = None,
updated_after: str | None = None,
updated_before: str | None = None,
limit: int | None = None,
offset: int | None = None
) -> PaginatedResponse[PaperSummary]
分页查询试卷。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
question_id
|
str | None
|
按包含的题目过滤。 |
None
|
category
|
str | None
|
按包含题目的分类过滤。 |
None
|
tag
|
str | None
|
按包含题目的标签过滤。 |
None
|
q
|
str | None
|
关键词,匹配 description、title、subtitle。 |
None
|
created_after
|
str | None
|
创建时间下限 (ISO 8601)。 |
None
|
created_before
|
str | None
|
创建时间上限 (ISO 8601)。 |
None
|
updated_after
|
str | None
|
更新时间下限 (ISO 8601)。 |
None
|
updated_before
|
str | None
|
更新时间上限 (ISO 8601)。 |
None
|
limit
|
int | None
|
每页数量 (1-100)。 |
None
|
offset
|
int | None
|
偏移量。 |
None
|
create_paper
¶
create_paper(
*,
description: str,
title: str,
subtitle: str,
question_ids: list[str],
file: str | Path | IO[bytes] | None = None
) -> PaperCreateResult
update_paper
¶
update_paper(
paper_id: str,
*,
description: str | None = None,
title: str | None = None,
subtitle: str | None = None,
question_ids: list[str] | None = None
) -> PaperDetail
部分更新试卷元数据。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
paper_id
|
str
|
试卷 UUID。 |
必需 |
description
|
str | None
|
试卷描述。 |
None
|
title
|
str | None
|
试卷标题。 |
None
|
subtitle
|
str | None
|
试卷副标题。 |
None
|
question_ids
|
list[str] | None
|
题目列表(更新后按数组顺序重排)。 |
None
|
replace_paper_file
¶
replace_paper_file(
paper_id: str, file: str | Path | IO[bytes]
) -> PaperFileReplaceResult
替换试卷附录 zip 文件。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
paper_id
|
str
|
试卷 UUID。 |
必需 |
file
|
str | Path | IO[bytes]
|
新的 zip 文件路径或二进制文件对象。 |
必需 |
download_paper_bundle
¶
批量打包下载试卷到本地。
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
paper_ids
|
list[str]
|
试卷 UUID 列表。 |
必需 |
save_to
|
str | Path
|
本地保存路径。 |
必需 |
返回:
| 类型 | 描述 |
|---|---|
Path
|
保存的文件路径。 |
异步客户端¶
AsyncQBClient
¶
AsyncQBClient(
base_url: str,
*,
access_token: str | None = None,
timeout: float = 30.0,
check_version: bool = True
)
Bases: AsyncAuthMixin, AsyncQuestionsMixin, AsyncPapersMixin
异步题库客户端,面向 bot 账号。
用法::
async with AsyncQBClient("http://localhost:8080", access_token="bot-token-xxx") as c:
questions = await c.list_questions(category="T")
search_users
async
¶
按关键词搜索用户。参见 AuthMixin.search_users。
list_questions
async
¶
list_questions(
*,
paper_id: str | None = None,
category: str | None = None,
tag: str | None = None,
author: str | None = None,
reviewer: str | None = None,
assigned_reviewer_id: str | None = None,
score_min: int | None = None,
score_max: int | None = None,
difficulty_tag: str | None = None,
difficulty_min: int | None = None,
difficulty_max: int | None = None,
q: str | None = None,
created_after: str | None = None,
created_before: str | None = None,
updated_after: str | None = None,
updated_before: str | None = None,
limit: int | None = None,
offset: int | None = None
) -> PaginatedResponse[QuestionSummary]
分页查询题目。参见 QuestionsMixin.list_questions。
create_question
async
¶
create_question(
file: str | Path | IO[bytes],
*,
description: str,
category: str | None = None,
tags: list[str] | None = None
) -> QuestionCreateResult
update_question_description
async
¶
update_question_description(
question_id: str, description: str
) -> QuestionDetail
update_question_category
async
¶
update_question_category(
question_id: str, category: str
) -> QuestionDetail
update_question_tags
async
¶
update_question_tags(
question_id: str, tags: list[str]
) -> QuestionDetail
update_question_status
async
¶
update_question_status(
question_id: str, status: str
) -> QuestionDetail
update_question_author
async
¶
update_question_author(
question_id: str, author: str
) -> QuestionDetail
update_question_reviewer_names
async
¶
update_question_reviewer_names(
question_id: str, reviewers: list[str]
) -> QuestionDetail
create_question_difficulty
async
¶
create_question_difficulty(
question_id: str,
algorithm_tag: str,
score: int,
*,
notes: str | None = None
) -> QuestionDetail
update_question_difficulty
async
¶
update_question_difficulty(
question_id: str,
algorithm_tag: str,
score: int,
*,
notes: str | None = None
) -> QuestionDetail
delete_question_difficulty
async
¶
delete_question_difficulty(
question_id: str, algorithm_tag: str
) -> QuestionDetail
replace_question_file
async
¶
replace_question_file(
question_id: str, file: str | Path | IO[bytes]
) -> QuestionFileReplaceResult
download_question_bundle
async
¶
list_papers
async
¶
list_papers(
*,
question_id: str | None = None,
category: str | None = None,
tag: str | None = None,
q: str | None = None,
created_after: str | None = None,
created_before: str | None = None,
updated_after: str | None = None,
updated_before: str | None = None,
limit: int | None = None,
offset: int | None = None
) -> PaginatedResponse[PaperSummary]
分页查询试卷。参见 PapersMixin.list_papers。
create_paper
async
¶
create_paper(
*,
description: str,
title: str,
subtitle: str,
question_ids: list[str],
file: str | Path | IO[bytes] | None = None
) -> PaperCreateResult
update_paper
async
¶
update_paper(
paper_id: str,
*,
description: str | None = None,
title: str | None = None,
subtitle: str | None = None,
question_ids: list[str] | None = None
) -> PaperDetail
replace_paper_file
async
¶
replace_paper_file(
paper_id: str, file: str | Path | IO[bytes]
) -> PaperFileReplaceResult