matelab-python-sdk 0.2.0a10__tar.gz → 0.3.0a2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/.agents/skills/matelab-sdk-release/SKILL.md +16 -11
  2. matelab_python_sdk-0.3.0a2/.python-version +1 -0
  3. matelab_python_sdk-0.3.0a2/.workflow/release.yml +61 -0
  4. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/AGENTS.md +2 -2
  5. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/PKG-INFO +8 -8
  6. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/README.md +4 -4
  7. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/contracts/matelab-integration-v1.lock.json +3 -3
  8. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/contracts/matelab-integration-v1.openapi.yaml +7 -7
  9. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/docs/agent-workflows.md +12 -10
  10. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/docs/api.md +5 -5
  11. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/docs/development.md +30 -7
  12. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/docs/operation-coverage.yaml +1 -1
  13. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/pyproject.toml +8 -8
  14. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/scripts/generate_models.py +1 -1
  15. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/_generated/models.py +2 -2
  16. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/_transport.py +6 -8
  17. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/_wire_validation.py +4 -5
  18. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/records.py +6 -7
  19. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_release.py +4 -4
  20. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_streaming.py +1 -1
  21. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_transport.py +1 -2
  22. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/uv.lock +157 -243
  23. matelab_python_sdk-0.2.0a10/.github/workflows/release.yml +0 -119
  24. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/.agents/skills/matelab-sdk-release/agents/openai.yaml +0 -0
  25. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/.agents/skills/matelab-sdk-release/scripts/verify_pypi.py +0 -0
  26. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/.env.example +0 -0
  27. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/.gitignore +0 -0
  28. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/CONTEXT.md +0 -0
  29. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/LICENSE +0 -0
  30. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/NOTICE +0 -0
  31. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/docs/agent-architecture.md +0 -0
  32. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/scripts/check_installed_package.py +0 -0
  33. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/scripts/check_release.py +0 -0
  34. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/__init__.py +0 -0
  35. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/_generated/__init__.py +0 -0
  36. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/_hashes.py +0 -0
  37. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/client.py +0 -0
  38. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/__init__.py +0 -0
  39. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/_attachment_content.py +0 -0
  40. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/cloud_drive.py +0 -0
  41. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/groups.py +0 -0
  42. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/literature.py +0 -0
  43. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/notebooks.py +0 -0
  44. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/templates.py +0 -0
  45. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/uploads.py +0 -0
  46. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/domains/users.py +0 -0
  47. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/errors.py +0 -0
  48. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/py.typed +0 -0
  49. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/session.py +0 -0
  50. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/src/matelab/streaming.py +0 -0
  51. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/conftest.py +0 -0
  52. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/provider/test_provider_smoke.py +0 -0
  53. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_async_attachment_upload.py +0 -0
  54. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_client.py +0 -0
  55. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_cloud_drive.py +0 -0
  56. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_comments_and_downloads.py +0 -0
  57. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_consumer_smoke.py +0 -0
  58. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_errors.py +0 -0
  59. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_extended_records.py +0 -0
  60. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_generation.py +0 -0
  61. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_groups.py +0 -0
  62. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_notebook_lifecycle.py +0 -0
  63. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_notebooks.py +0 -0
  64. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_operation_coverage.py +0 -0
  65. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_record_lifecycle.py +0 -0
  66. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_record_mutations.py +0 -0
  67. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_records.py +0 -0
  68. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_template_lifecycle.py +0 -0
  69. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_templates.py +0 -0
  70. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_uploads_and_literature.py +0 -0
  71. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/test_users.py +0 -0
  72. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/typing/consumer.py +0 -0
  73. {matelab_python_sdk-0.2.0a10 → matelab_python_sdk-0.3.0a2}/tests/typing/pyproject.toml +0 -0
@@ -34,7 +34,8 @@ coverage 和当前态文档。公开接口和生命周期沿 public intent → w
34
34
  ## 2. 验证与审查
35
35
 
36
36
  执行 `docs/agent-workflows.md#delivery-gate`,具体命令取 `docs/development.md#development`。
37
- 代码、契约、依赖或构建行为变化先聚焦再完整测试;聚焦用例不能代替完整 `pytest`。修复需补充的用例来自契约、
37
+ 代码、契约、依赖或构建行为变化先聚焦再完整测试;聚焦用例不能代替完整 `pytest`。发布前的支持版本测试、静态
38
+ 检查和安装后消费验证在本地完成,发布 CI 不重复执行。修复需补充的用例来自契约、
38
39
  独立示例或可验证属性,不复刻实现,不增加 Provider 逐路由 conformance。
39
40
 
40
41
  真实 smoke 按 `docs/agent-workflows.md#provider-validation` 确认目标、ignore 和授权。授权覆盖隔离服务的登录、
@@ -57,21 +58,25 @@ commit/diff;只改版本后补版本一致性检查,不重跑未受影响的
57
58
  SDK 版本与 spec 日历版本独立,不跳过未占用的预发布序号。`pyproject.toml` 是唯一版本来源,更新 `uv.lock` 的
58
59
  本项目版本。仅改版本时保持其余 lock 内容,使用发布 workflow 固定的 uv 检查兼容性。
59
60
 
60
- 按需读配置/依赖章节;不因发布顺手升级依赖、Node 或 Actions。文档在提交前完成,仅维护受影响的当前态,不新建
61
- CHANGELOG。正常发布由 CI 完成可复现构建、制品审计和安装后消费;只有打包故障或打包配置变化需要时才本地构建,
62
- 使用临时目录,不积累 `dist/`。
61
+ 按需读配置/依赖章节;不因发布顺手升级依赖、Node、uv 或流水线插件。文档在提交前完成,仅维护受影响的当前态,不新建
62
+ CHANGELOG。本地为发布前消费验证、打包故障或打包配置变化按需构建,使用临时目录,不积累 `dist/`。
63
63
 
64
64
  复核最终 diff、版本、Contract pin 和有效验证证据,将本次尚未提交的实现、测试、文档及版本号放入同一个
65
65
  release commit。已有提交的历史仅在另有授权时改写。
66
66
 
67
- ## 4. 推送、发布并核验
67
+ ## 4. 推送与自动发布
68
68
 
69
- 执行 `docs/agent-workflows.md#release`:创建指向 release commit 的 annotated `v{version}` tag,按规定顺序推送
70
- 同一 branch/tag 到两个远端,并验证远端 refs。跟踪该 commit/tag 的发布 workflow,逐项确认测试、可复现构建、
71
- 制品审计、安装后消费和 PyPI 上传成功;tag 推送成功不等于发布完成。
69
+ 本地验证通过后,按 `docs/agent-workflows.md#release` 完成:
72
70
 
73
- 使用可用的 GitHub 工具读取 jobs 和构建日志;能力不足时用 `gh`。从本次 CI 构建审计输出或下载的 CI 制品取得
74
- wheel/sdist 的 SHA-256,不能仅用 PyPI 自报哈希证明 CI/PyPI 一致。在 SDK 锁定开发环境中运行本技能的只读核验器:
71
+ 1. 创建指向本次 release commit 的新 annotated `v{version}` tag,版本与 `pyproject.toml` 一致。
72
+ 2. 推送 `origin` 的 main 和本次新 tag,核对远端 refs 均对应本次 release commit。
73
+ 3. 跟踪新 tag 自动触发的 Gitee 流水线,由其完成可复现构建、制品审计和 PyPI 上传;CI 不重复本地验证。
74
+
75
+ 已发布版本不可覆盖,对应 tag 不再移动。main 可以继续前进,无需与历史 tag 指向同一提交;
76
+ 后续发版使用新版本、新 tag。
77
+
78
+ 从本次 CI 构建审计输出或下载的制品取得 wheel/sdist 的 SHA-256,不能仅用 PyPI 自报哈希证明 CI/PyPI 一致。
79
+ 在 SDK 锁定开发环境中运行本技能的只读核验器:
75
80
 
76
81
  ```bash
77
82
  uv run --frozen --no-sync python -B .agents/skills/matelab-sdk-release/scripts/verify_pypi.py \
@@ -85,5 +90,5 @@ uv run --frozen --no-sync python -B .agents/skills/matelab-sdk-release/scripts/v
85
90
  历史制品。PyPI 暂未可读时允许短暂重试,等待期间保持进度更新。
86
91
 
87
92
  失败时定位具体阶段,优先重试失败环节;不通过删测试、跳检查或自动另选版本制造成功。改变已推送历史或处理失败
88
- 候选前核对现有授权,已发布版本不可覆盖。最后报告版本/链接、单次提交、两个远端 refs、CI/PyPI 核验和工作区状态;
93
+ 候选前核对现有授权。最后报告版本/链接、发布提交、main 与新 tag 的远端 refs、Gitee/PyPI 核验和工作区状态;
89
94
  明确剩余失败或未验证项。
@@ -0,0 +1 @@
1
+ 3.15
@@ -0,0 +1,61 @@
1
+ version: "1.0"
2
+ name: sdk-release
3
+ displayName: Publish SDK to PyPI
4
+ ref_variable:
5
+ - UV_PUBLISH_TOKEN
6
+ triggers:
7
+ push:
8
+ tags:
9
+ prefix:
10
+ - v
11
+ stages:
12
+ - name: release
13
+ displayName: Build and publish
14
+ strategy: naturally
15
+ trigger: auto
16
+ steps:
17
+ - step: build@python
18
+ name: build-and-publish
19
+ displayName: Build and publish release
20
+ # Gitee's Python bootstraps uv; the SDK runs on uv-managed Python 3.15.
21
+ pythonVersion: "3.14"
22
+ commands: |
23
+ set +x
24
+ set -eu
25
+ # Keep Gitee's Python tooling out of the build environment.
26
+ unset PYTHONPATH PYTHONHOME
27
+ python -m pip install --user --index-url https://pypi.org/simple "uv==0.13.7"
28
+ export PATH="$(python -m site --user-base)/bin:$PATH"
29
+ uv --version
30
+ release_tag="v$(uv version --short)"
31
+ build_ref="${GITEE_BRANCH:?Gitee build ref is required}"
32
+ if [ "$build_ref" != "$release_tag" ]; then
33
+ echo "Release ref must be $release_tag; received $build_ref" >&2
34
+ exit 1
35
+ fi
36
+ if [ "$(git rev-parse HEAD)" != "${GITEE_COMMIT:?Gitee trigger commit is required}" ]; then
37
+ echo "Checkout does not match the Gitee build commit" >&2
38
+ exit 1
39
+ fi
40
+ : "${UV_PUBLISH_TOKEN:?Configure UV_PUBLISH_TOKEN as a protected pipeline secret}"
41
+ export SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)"
42
+ export UV_PYTHON="$(cat .python-version)"
43
+ uv sync --frozen
44
+
45
+ mkdir -p dist/release dist/reproducible
46
+ uv build --no-build-isolation --out-dir dist/release
47
+ uv build --no-build-isolation --out-dir dist/reproducible
48
+ cmp dist/release/*.whl dist/reproducible/*.whl
49
+ cmp dist/release/*.tar.gz dist/reproducible/*.tar.gz
50
+ uv run --frozen python scripts/check_release.py dist/release/*.whl dist/release/*.tar.gz
51
+ (cd dist/release && sha256sum *.whl *.tar.gz > SHA256SUMS)
52
+ cat dist/release/SHA256SUMS
53
+
54
+ uv publish --trusted-publishing never \
55
+ --publish-url https://upload.pypi.org/legacy/ \
56
+ dist/release/*.whl dist/release/*.tar.gz
57
+ artifacts:
58
+ - name: RELEASE_ARTIFACT
59
+ path:
60
+ - ./dist/release
61
+ type: .tar.gz
@@ -12,8 +12,8 @@
12
12
  4. **验证**:按变更类型执行 [delivery gate](docs/agent-workflows.md#delivery-gate),复用仍覆盖当前变更的有效结果。
13
13
  5. **交付**:复核最终 diff 和状态,报告结果、验证证据、限制及未执行项。
14
14
 
15
- 本地仅为打包配置、构建元数据、发布脚本变化或制品故障按需构建。正式可复现构建、制品审计和安装后消费由
16
- 发布 CI 执行,本地无需重复构建或保留历史 `dist/` 产物。
15
+ 发布前在本地完成测试、静态检查和安装后消费验证;发布 CI 只负责可复现构建、制品审计和 PyPI 上传。
16
+ 本地为发布前消费验证、打包配置或制品故障按需构建,使用临时目录,不保留历史 `dist/` 产物。
17
17
 
18
18
  ## 分支指针
19
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matelab-python-sdk
3
- Version: 0.2.0a10
3
+ Version: 0.3.0a2
4
4
  Summary: Reusable async Python client for the Matelab Integration Contract
5
5
  Author: CMPDC, Institute of Physics, Chinese Academy of Sciences
6
6
  License-Expression: Apache-2.0
@@ -12,24 +12,24 @@ Classifier: Framework :: AsyncIO
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3 :: Only
15
- Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
18
17
  Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
19
  Classifier: Topic :: Scientific/Engineering
20
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
21
  Classifier: Typing :: Typed
22
- Requires-Python: >=3.11
22
+ Requires-Python: >=3.12
23
23
  Requires-Dist: httpx2>=2.16.0
24
24
  Requires-Dist: jsonschema>=4.26.0
25
- Requires-Dist: pydantic>=2.14.1
25
+ Requires-Dist: pydantic>=2.14.3
26
26
  Requires-Dist: typing-extensions>=4.16.0
27
27
  Description-Content-Type: text/markdown
28
28
 
29
29
  # matelab-python-sdk
30
30
 
31
31
  Async Python client for the Matelab Integration Contract, with typed interfaces for authentication,
32
- notebooks, records, attachments, cloud files, templates, and literature. Requires Python 3.11 or newer.
32
+ notebooks, records, attachments, cloud files, templates, and literature. Requires Python 3.12 or newer.
33
33
 
34
34
  ## Installation
35
35
 
@@ -64,6 +64,6 @@ asyncio.run(main())
64
64
 
65
65
  ## Documentation
66
66
 
67
- - [API reference](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/api.md): Session persistence, errors, examples, and Provider limits.
68
- - [Operation coverage](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/operation-coverage.yaml): supported operations.
69
- - [Development and releases](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/development.md): checks, Provider smoke, versioning, and builds.
67
+ - [API reference](https://gitee.com/mat-code/matelab-python-sdk/blob/main/docs/api.md): Session persistence, errors, examples, and Provider limits.
68
+ - [Operation coverage](https://gitee.com/mat-code/matelab-python-sdk/blob/main/docs/operation-coverage.yaml): supported operations.
69
+ - [Development and releases](https://gitee.com/mat-code/matelab-python-sdk/blob/main/docs/development.md): checks, Provider smoke, versioning, and builds.
@@ -1,7 +1,7 @@
1
1
  # matelab-python-sdk
2
2
 
3
3
  Async Python client for the Matelab Integration Contract, with typed interfaces for authentication,
4
- notebooks, records, attachments, cloud files, templates, and literature. Requires Python 3.11 or newer.
4
+ notebooks, records, attachments, cloud files, templates, and literature. Requires Python 3.12 or newer.
5
5
 
6
6
  ## Installation
7
7
 
@@ -36,6 +36,6 @@ asyncio.run(main())
36
36
 
37
37
  ## Documentation
38
38
 
39
- - [API reference](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/api.md): Session persistence, errors, examples, and Provider limits.
40
- - [Operation coverage](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/operation-coverage.yaml): supported operations.
41
- - [Development and releases](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/development.md): checks, Provider smoke, versioning, and builds.
39
+ - [API reference](https://gitee.com/mat-code/matelab-python-sdk/blob/main/docs/api.md): Session persistence, errors, examples, and Provider limits.
40
+ - [Operation coverage](https://gitee.com/mat-code/matelab-python-sdk/blob/main/docs/operation-coverage.yaml): supported operations.
41
+ - [Development and releases](https://gitee.com/mat-code/matelab-python-sdk/blob/main/docs/development.md): checks, Provider smoke, versioning, and builds.
@@ -2,12 +2,12 @@
2
2
  "schema_version": 1,
3
3
  "contract_line": "integration-v1",
4
4
  "release": {
5
- "tag": "v2026.11.2",
6
- "commit": "a986f73b0edc6bb67f2993a9ee1291aba31df5e5"
5
+ "tag": "v2026.11.4",
6
+ "commit": "199f1ae307e0561bd7c4ec8ce5af22d05486e7e9"
7
7
  },
8
8
  "openapi": {
9
9
  "source_path": "openapi/matelab-integration-v1.openapi.yaml",
10
10
  "snapshot": "matelab-integration-v1.openapi.yaml",
11
- "sha256": "4a485f0ab2b589136cdcccad77407d8b5768e6e8cbb8e3a7636d8b9a07649991"
11
+ "sha256": "769629096ccdd9d4198aefd738e522afa268ec77a146cf4548fc3b1715985b49"
12
12
  }
13
13
  }
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: Matelab Integration Contract
4
- version: "2026.11.2"
4
+ version: "2026.11.4"
5
5
  description: |
6
6
  Current PHP wire contract for generating SDKs against the selected
7
7
  `matelab-server` Provider version.
@@ -18,7 +18,7 @@ info:
18
18
  x-contract-line: integration-v1
19
19
  x-provider-evidence:
20
20
  repository: /home/tnzhu/projects/matelab-server
21
- commit: f5a714e17cd76076efe7579db279936ac29b50a6
21
+ commit: fa4172020c6a9f2955ed02a763bfce909ef63aa3
22
22
  verificationRuntime:
23
23
  baseUrl: https://matelab.iphy.ac.cn/eln-test/api
24
24
  container: matelab-test-server-1
@@ -53,6 +53,7 @@ info:
53
53
  - lib/Route.php
54
54
  - lib/HttpServer.php
55
55
  - lib/WsServer.php
56
+ - lib/Taskscheduler.php
56
57
  - start.php
57
58
  - lib/MultiException.php
58
59
  - config/Db.php
@@ -62,17 +63,16 @@ info:
62
63
  - sql/matelab.sql
63
64
  - sql/recommend.sql
64
65
  x-provider-audit:
65
- currentCommit: f5a714e17cd76076efe7579db279936ac29b50a6
66
- previousReleaseEvidenceCommit: 00f17b6ce0906bb78b0a3e9bb8c50abee90ca3d0
67
- lastProviderVerifiedCommit: f5a714e17cd76076efe7579db279936ac29b50a6
66
+ currentCommit: fa4172020c6a9f2955ed02a763bfce909ef63aa3
67
+ previousReleaseEvidenceCommit: f5a714e17cd76076efe7579db279936ac29b50a6
68
+ lastProviderVerifiedCommit: fa4172020c6a9f2955ed02a763bfce909ef63aa3
68
69
  contractStatus: current-provider-aligned
69
70
  # Summary of changes adopted by current Supported Routes since the last
70
71
  # released contract, including contract corrections. The Provider diff is
71
72
  # previousReleaseEvidenceCommit -> currentCommit. Accumulate unreleased
72
73
  # updates against that fixed release baseline; use [] if no relevant changes.
73
74
  # Entries are not per-change verification results or a cumulative history.
74
- incorporatedChanges:
75
- - {operationId: stageTemporaryFile, change: filename-independent-continuation-with-final-fragment-name-and-extensionless-abort}
75
+ incorporatedChanges: []
76
76
  x-consumer-evidence:
77
77
  - repository: /home/tnzhu/projects/matelab-mcp
78
78
  commit: 94a129b2df0ef0fbcf179c10550fb7c9a5dd2e6f
@@ -31,8 +31,9 @@
31
31
  - `[tool.basedpyright]` 字段依次为 `pythonVersion`、`typeCheckingMode`、`include`、`exclude`、
32
32
  `reportUnannotatedClassAttribute`、`reportIncompatibleUnannotatedOverride`,其他设置放在其后。沿用 SDK 的目标
33
33
  Python 版本与检查路径,不照搬其他项目的值。
34
- - runtime、build 和 dev 依赖仅声明已验证的 `>=` 下限;`nodejs-wheel-binaries` 保留系统所需的精确版本。
35
- 更新声明时同步 lock 和安装后消费检查使用的 CI requirement。
34
+ - 升级 runtime、build 或 dev 依赖时,必须将验证通过的新版本同步为 `pyproject.toml` 中对应依赖的 `>=` 下限,
35
+ 同时更新对应 CI 和本地安装后消费校验中的约束。`uv.lock` 必须通过 `uv lock` 等 uv 命令自动更新,不手工编辑。
36
+ 例外:`nodejs-wheel-binaries` 保留系统所需的精确版本,并同步 lock 和对应 CI 约束。
36
37
  - 构建后端依赖和 wheel package 显式配置;metadata 与制品检查从这些声明推导预期值。
37
38
 
38
39
  完成标准:配置可解析、声明与 lock 一致、受影响 CI 使用同一约束;字段重排不改变配置含义。
@@ -85,16 +86,17 @@ Ruff/Basedpyright 诊断通过修复代码或精确 ignore 解决,不缩小检
85
86
  ## Release
86
87
 
87
88
  普通 commit/push 只处理已授权的 diff,不自动改版本、建 tag 或发布。发布准备完成但缺少外部操作授权时,
88
- 先交付可审查结果,再请求执行授权。以下步骤适用于实际发布:
89
+ 先交付可审查结果,再请求执行授权。发布与普通推送只同步 `origin`。以下步骤适用于实际发布:
89
90
 
90
91
  1. 按 [版本规则](development.md#versioning) 选择 SDK 版本,读取 `[project].version`,确认待发布版本未发布
91
92
  且 Contract pin 完整。公开接口删除、重命名、类型收紧或不兼容行为变化按 breaking change 处理。
92
93
  完成标准:版本、当前文档和 tag 名 `v{version}` 一致。
93
- 2. 提交前同步受影响的当前文档,完成 [delivery gate](#delivery-gate)。构建元数据或发布流程变化时,核对
94
- metadata 版本与固定的 PyPI 发布 Action 是否兼容;需要本地制品证据时使用
94
+ 2. 提交前同步受影响的当前文档,在本地完成 [delivery gate](#delivery-gate)、支持版本测试与安装后消费校验。
95
+ 构建元数据或发布流程变化时,核对
96
+ metadata 与流水线固定版本的 uv 是否兼容;需要本地制品证据时使用
95
97
  [手工构建命令](development.md#reproducible-release-build)。创建已审查、已授权的 release commit。
96
- 3. 创建指向 release commit 的 annotated `v{version}` tag。先推送 `origin` 的 main/tag,再推送 GitHub mirror 的
97
- main/tag;只有与项目版本完全匹配的 tag 触发 Trusted Publishing workflow,第三方 Action 固定 immutable
98
- commit SHA。
99
- 4. 跟踪 [发布 CI](../.github/workflows/release.yml) 的测试、可复现构建、制品审计、安装后消费和 PyPI publish。
100
- 完成标准:两个远端 main/tag 对应 release commit,CI 全部通过,PyPI 对应版本可读取。
98
+ 3. 本地验证通过后,创建指向 release commit 的新 annotated `v{version}` tag,推送 `origin` 的 main 和新 tag;
99
+ tag 推送自动触发 Gitee [发布 CI](../.workflow/release.yml)。已发布版本不可覆盖,对应 tag 不再移动;main 可继续
100
+ 前进,无需与旧 tag 指向同一提交,后续发版使用新版本、新 tag。
101
+ 4. 跟踪新 tag 的 Gitee 可复现构建、制品审计和 PyPI 上传;CI 不重复本地测试、静态检查或消费校验。
102
+ 完成标准:本地验证通过,本次推送的 main/新 tag 对应 release commit,Gitee 发布成功,PyPI 与 CI 制品哈希一致。
@@ -5,13 +5,13 @@ See the [README](../README.md) for installation and quick start and [CONTEXT.md]
5
5
 
6
6
  ## Contract
7
7
 
8
- The SDK is pinned to the immutable `matelab-spec v2026.11.2` Contract Release. The sole pin,
8
+ The SDK is pinned to the immutable `matelab-spec v2026.11.4` Contract Release. The sole pin,
9
9
  [contracts/matelab-integration-v1.lock.json](../contracts/matelab-integration-v1.lock.json), records peeled commit
10
- `a986f73b0edc6bb67f2993a9ee1291aba31df5e5`, source `openapi/matelab-integration-v1.openapi.yaml`, the local snapshot path,
11
- and SHA-256 `4a485f0ab2b589136cdcccad77407d8b5768e6e8cbb8e3a7636d8b9a07649991`. The annotated tag object is
12
- `dc7a09dccf4187100cd05241757fc3f500107bdd`.
10
+ `199f1ae307e0561bd7c4ec8ce5af22d05486e7e9`, source `openapi/matelab-integration-v1.openapi.yaml`, the local snapshot path,
11
+ and SHA-256 `769629096ccdd9d4198aefd738e522afa268ec77a146cf4548fc3b1715985b49`. The annotated tag object is
12
+ `b1748d96763669461cfa9467d6a4cd1273f53b41`.
13
13
 
14
- The Contract uses Provider source evidence from `f5a714e17cd76076efe7579db279936ac29b50a6`; v2026.11.2 validation ran
14
+ The Contract uses Provider source evidence from `fa4172020c6a9f2955ed02a763bfce909ef63aa3`; v2026.11.4 validation ran
15
15
  against an isolated test instance and does not establish production behavior. The Front Consumer evidence
16
16
  `f7a7b952d7981f169d5c2585aea5c94b418086a3` informs cross-Consumer capability review but does not define the SDK interface.
17
17
 
@@ -15,6 +15,11 @@ according to its public impact.
15
15
 
16
16
  ## Development
17
17
 
18
+ Use Python 3.15 for development; `.python-version` selects it for `uv sync` and `uv run`.
19
+ The SDK supports Python 3.12 and newer. Source syntax, type checking, and generated models target Python 3.12.
20
+ Run tests and static checks locally before release. Generated-model, lint, formatting, and type checks use Python 3.15.
21
+ Release CI uses Python 3.15 for reproducible builds, artifact audits, and PyPI upload; it does not rerun tests.
22
+
18
23
  ```bash
19
24
  uv sync --frozen
20
25
  uv run python scripts/generate_models.py --check
@@ -28,6 +33,17 @@ Choose checks by change type using the
28
33
  [maintenance workflows](agent-workflows.md#delivery-gate).
29
34
  Contract or generator changes regenerate private models with `uv run python scripts/generate_models.py` before checking.
30
35
  `pyproject.toml` declares dependency minimums; `uv.lock` fixes the development and release environment.
36
+ The exact Node.js wheel pin preserves compatibility with glibc 2.17 on the development host.
37
+
38
+ Before release, also test all supported Python versions locally, with Provider connection variables unset:
39
+
40
+ ```bash
41
+ test_status=0
42
+ for python_version in 3.12 3.13 3.14 3.15; do
43
+ uv run --frozen --exact --python "$python_version" pytest -rs || test_status=1
44
+ done
45
+ test "$test_status" -eq 0
46
+ ```
31
47
 
32
48
  ## Opt-in Provider consumer smoke
33
49
 
@@ -51,18 +67,25 @@ for target authorization and keep credentials out of Git.
51
67
 
52
68
  ## Reproducible release build
53
69
 
54
- A `v*` release tag pushed to GitHub triggers CI to build twice, compare wheel/sdist bytes, audit artifacts, verify an
55
- installed-wheel consumer, and publish to PyPI. Preparation follows the
70
+ After local validation, pushing a `v{version}` release tag to `origin` automatically triggers
71
+ [CI](../.workflow/release.yml): reproducible builds, artifact audits, and PyPI publishing.
72
+ The workflow accepts only the tag matching the declared version. Preparation follows the
56
73
  [release workflow](agent-workflows.md#release).
57
74
 
58
- Local builds are only needed for packaging changes or artifact diagnostics. To reproduce CI artifacts, use the release
59
- tag's checkout and committer timestamp, the locked environment, and a temporary output directory:
75
+ For local installed-wheel validation or packaging diagnostics, use the intended release checkout and committer
76
+ timestamp, the locked environment, and a temporary output directory:
60
77
 
61
78
  ```bash
62
79
  export SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)"
63
80
  sdk_release_build_dir="$(mktemp -d)"
81
+ trap 'rm -rf -- "$sdk_release_build_dir"' EXIT
64
82
  uv sync --frozen
65
- uv build --no-build-isolation --out-dir "$sdk_release_build_dir"
66
- uv run python scripts/check_release.py "$sdk_release_build_dir"/*.whl "$sdk_release_build_dir"/*.tar.gz
67
- (cd "$sdk_release_build_dir" && sha256sum *.whl *.tar.gz > SHA256SUMS)
83
+ uv build --no-build-isolation --out-dir "$sdk_release_build_dir/dist"
84
+ uv run python scripts/check_release.py "$sdk_release_build_dir"/dist/*.whl "$sdk_release_build_dir"/dist/*.tar.gz
85
+ uv venv --python 3.15 "$sdk_release_build_dir/consumer"
86
+ uv pip install --python "$sdk_release_build_dir/consumer/bin/python" \
87
+ "$sdk_release_build_dir"/dist/*.whl "basedpyright>=1.40.2" "nodejs-wheel-binaries==22.20.0"
88
+ "$sdk_release_build_dir/consumer/bin/python" scripts/check_installed_package.py
89
+ "$sdk_release_build_dir/consumer/bin/basedpyright" \
90
+ --pythonpath "$sdk_release_build_dir/consumer/bin/python" --project tests/typing/pyproject.toml
68
91
  ```
@@ -3,7 +3,7 @@
3
3
  schema_version: 1
4
4
  contract:
5
5
  line: integration-v1
6
- release: v2026.11.2
6
+ release: v2026.11.4
7
7
  operation_count: 71
8
8
 
9
9
  operations:
@@ -4,9 +4,9 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "matelab-python-sdk"
7
- version = "0.2.0a10"
7
+ version = "0.3.0a2"
8
8
  description = "Reusable async Python client for the Matelab Integration Contract"
9
- requires-python = ">=3.11"
9
+ requires-python = ">=3.12"
10
10
  keywords = ["matelab", "electronic-lab-notebook", "eln", "asyncio", "sdk"]
11
11
  authors = [
12
12
  { name = "CMPDC, Institute of Physics, Chinese Academy of Sciences" },
@@ -14,7 +14,7 @@ authors = [
14
14
  dependencies = [
15
15
  "httpx2>=2.16.0",
16
16
  "jsonschema>=4.26.0",
17
- "pydantic>=2.14.1",
17
+ "pydantic>=2.14.3",
18
18
  "typing-extensions>=4.16.0",
19
19
  ]
20
20
  readme = "README.md"
@@ -26,10 +26,10 @@ classifiers = [
26
26
  "Operating System :: OS Independent",
27
27
  "Programming Language :: Python :: 3",
28
28
  "Programming Language :: Python :: 3 :: Only",
29
- "Programming Language :: Python :: 3.11",
30
29
  "Programming Language :: Python :: 3.12",
31
30
  "Programming Language :: Python :: 3.13",
32
31
  "Programming Language :: Python :: 3.14",
32
+ "Programming Language :: Python :: 3.15",
33
33
  "Topic :: Scientific/Engineering",
34
34
  "Topic :: Software Development :: Libraries :: Python Modules",
35
35
  "Typing :: Typed",
@@ -39,12 +39,12 @@ classifiers = [
39
39
  dev = [
40
40
  "basedpyright>=1.40.2",
41
41
  "nodejs-wheel-binaries==22.20.0",
42
- "datamodel-code-generator>=0.87.0",
42
+ "datamodel-code-generator>=0.90.0",
43
43
  "hatchling>=1.33.0",
44
44
  "pytest>=9.2.0",
45
- "pytest-asyncio>=1.4.1",
45
+ "pytest-asyncio>=1.4.1.post1",
46
46
  "pyyaml>=6.0.3",
47
- "ruff>=0.17.3",
47
+ "ruff>=0.17.4",
48
48
  ]
49
49
 
50
50
  [tool.ruff]
@@ -54,7 +54,7 @@ lint.isort.split-on-trailing-comma = false
54
54
  format.skip-magic-trailing-comma = true
55
55
 
56
56
  [tool.basedpyright]
57
- pythonVersion = "3.11"
57
+ pythonVersion = "3.12"
58
58
  typeCheckingMode = "recommended"
59
59
  include = ["src", "tests", "scripts"]
60
60
  exclude = ["src/matelab/_generated"]
@@ -451,7 +451,7 @@ def _render_models(document: dict[str, Any]) -> bytes:
451
451
  "--base-class",
452
452
  "matelab._wire_validation.WireModel",
453
453
  "--target-python-version",
454
- "3.11",
454
+ "3.12",
455
455
  "--disable-future-imports",
456
456
  "--use-union-operator",
457
457
  "--use-standard-collections",
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # @generated by datamodel-codegen:
4
4
  # filename: openapi.yaml
5
- # version: 0.87.0
5
+ # version: 0.90.0
6
6
 
7
7
  from enum import StrEnum
8
8
  from typing import Annotated, Any, Literal
@@ -11,7 +11,7 @@ from pydantic import ConfigDict, Field, RootModel, SecretStr, StrictBool, Strict
11
11
 
12
12
  from matelab._wire_validation import WireModel
13
13
 
14
- OPENAPI_INFO_VERSION = "2026.11.2"
14
+ OPENAPI_INFO_VERSION = "2026.11.4"
15
15
 
16
16
 
17
17
  class ResponseEnvelope(WireModel):
@@ -5,11 +5,10 @@ from collections.abc import AsyncIterator, Mapping
5
5
  from contextlib import suppress
6
6
  from dataclasses import dataclass
7
7
  from enum import StrEnum
8
- from typing import IO, Generic, TypeAlias, TypeVar, cast
8
+ from typing import IO, cast, override
9
9
 
10
10
  from httpx2 import AsyncByteStream, AsyncClient, Request, RequestError, Response, SyncByteStream
11
11
  from pydantic import BaseModel, JsonValue, SecretStr, ValidationError
12
- from typing_extensions import override
13
12
 
14
13
  from matelab._generated import models as wire_models
15
14
  from matelab.errors import (
@@ -23,10 +22,9 @@ from matelab.errors import (
23
22
  from matelab.session import Session, Token
24
23
  from matelab.streaming import ByteRange, DownloadStream
25
24
 
26
- WireResponse = TypeVar("WireResponse", bound=BaseModel)
27
25
  _ACCESS_EXPIRY_SKEW_MS = 30_000
28
- _ParameterValue: TypeAlias = str | int | float | bool | None
29
- _Files: TypeAlias = Mapping[str, tuple[str, IO[bytes] | bytes, str]]
26
+ type _ParameterValue = str | int | float | bool | None
27
+ type _Files = Mapping[str, tuple[str, IO[bytes] | bytes, str]]
30
28
  _CONTENT_RANGE_PATTERN = re.compile(r"^bytes [0-9]+-[0-9]+/[0-9]+$")
31
29
 
32
30
 
@@ -100,7 +98,7 @@ class Encoding(StrEnum):
100
98
 
101
99
 
102
100
  @dataclass(frozen=True, slots=True)
103
- class Operation(Generic[WireResponse]):
101
+ class Operation[WireResponse: BaseModel]:
104
102
  method: str
105
103
  path: str
106
104
  encoding: Encoding
@@ -177,7 +175,7 @@ class SessionTransport:
177
175
  )
178
176
  return self.session
179
177
 
180
- async def _send_multipart(
178
+ async def _send_multipart[WireResponse: BaseModel](
181
179
  self,
182
180
  operation: Operation[WireResponse],
183
181
  *,
@@ -205,7 +203,7 @@ class SessionTransport:
205
203
  request.stream = _ThreadedMultipartStream(request.stream)
206
204
  return await self._http.send(request)
207
205
 
208
- async def request(
206
+ async def request[WireResponse: BaseModel](
209
207
  self, operation: Operation[WireResponse], *, payload: BaseModel | None = None, files: _Files | None = None
210
208
  ) -> WireResponse:
211
209
  if (
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from collections.abc import Callable, Collection, Iterator, Mapping
3
- from typing import TypeAlias, TypeVar, cast
3
+ from typing import cast
4
4
 
5
5
  from jsonschema import Draft202012Validator
6
6
  from jsonschema.exceptions import ValidationError as JsonSchemaValidationError
@@ -15,8 +15,7 @@ from matelab.errors import MatelabUsageError
15
15
 
16
16
  _RUNTIME_RULES_KEY = "matelab-runtime-rules"
17
17
  JsonObject = dict[str, JsonValue]
18
- WireValue: TypeAlias = JsonValue | bytes | Mapping[str, "WireValue"]
19
- ModelT = TypeVar("ModelT", bound=BaseModel)
18
+ type WireValue = JsonValue | bytes | Mapping[str, WireValue]
20
19
 
21
20
 
22
21
  def _reject_json_constant(_value: str) -> None:
@@ -44,7 +43,7 @@ _ContractValidator = cast(
44
43
  )
45
44
 
46
45
 
47
- def validate_request(model: type[ModelT], data: Mapping[str, WireValue], message: str) -> ModelT:
46
+ def validate_request[ModelT: BaseModel](model: type[ModelT], data: Mapping[str, WireValue], message: str) -> ModelT:
48
47
  """Validate caller input without exposing it in the public exception."""
49
48
  try:
50
49
  return model.model_validate(data)
@@ -52,7 +51,7 @@ def validate_request(model: type[ModelT], data: Mapping[str, WireValue], message
52
51
  raise MatelabUsageError(message) from None
53
52
 
54
53
 
55
- def validate_multipart_request(
54
+ def validate_multipart_request[ModelT: BaseModel](
56
55
  model: type[ModelT], data: Mapping[str, WireValue], file_fields: Collection[str], message: str
57
56
  ) -> ModelT:
58
57
  """Validate multipart fields whose binary content is transported separately."""
@@ -5,11 +5,10 @@ from copy import deepcopy
5
5
  from dataclasses import dataclass, field
6
6
  from html.parser import HTMLParser
7
7
  from types import MappingProxyType
8
- from typing import IO, Literal, Self, TypeAlias, cast
8
+ from typing import IO, Literal, Self, cast, override
9
9
  from urllib.parse import unquote
10
10
 
11
11
  from pydantic import BaseModel, JsonValue, model_validator
12
- from typing_extensions import override
13
12
 
14
13
  from matelab._generated import models as wire_models
15
14
  from matelab._hashes import LOWERCASE_SHA256_PATTERN
@@ -426,7 +425,7 @@ class StagedAttachment:
426
425
  raise ValueError("Staged attachment metadata is invalid.")
427
426
 
428
427
 
429
- RecordImportValue: TypeAlias = (
428
+ type RecordImportValue = (
430
429
  str
431
430
  | int
432
431
  | float
@@ -434,9 +433,9 @@ RecordImportValue: TypeAlias = (
434
433
  | None
435
434
  | StagedAttachment
436
435
  | CloudFile
437
- | Mapping[str, "RecordImportValue"]
438
- | list["RecordImportValue"]
439
- | tuple["RecordImportValue", ...]
436
+ | Mapping[str, RecordImportValue]
437
+ | list[RecordImportValue]
438
+ | tuple[RecordImportValue, ...]
440
439
  )
441
440
 
442
441
 
@@ -563,7 +562,7 @@ class RecordTableFileColumnDeletion:
563
562
  name: str
564
563
 
565
564
 
566
- RecordChange: TypeAlias = (
565
+ type RecordChange = (
567
566
  RecordValueUpdate
568
567
  | RecordValueDeletion
569
568
  | RecordModuleCreation
@@ -129,9 +129,9 @@ def test_release_dependencies_publish_minimum_versions() -> None:
129
129
  assert build == [dev["hatchling"]]
130
130
  assert project["license"] == "Apache-2.0"
131
131
  assert project["license-files"] == ["LICENSE", "NOTICE"]
132
- workflow = (_ROOT / ".github" / "workflows" / "release.yml").read_text()
133
- assert str(dev["basedpyright"]) in workflow
134
- assert str(dev["nodejs-wheel-binaries"]) in workflow
132
+ development = (_ROOT / "docs" / "development.md").read_text()
133
+ assert str(dev["basedpyright"]) in development
134
+ assert str(dev["nodejs-wheel-binaries"]) in development
135
135
 
136
136
 
137
137
  def test_built_metadata_contains_public_dependency_and_python_contract(built_wheel: Path) -> None:
@@ -141,7 +141,7 @@ def test_built_metadata_contains_public_dependency_and_python_contract(built_whe
141
141
 
142
142
  assert metadata["Name"] == "matelab-python-sdk"
143
143
  assert metadata["Version"] == _RELEASE_VERSION
144
- assert metadata["Requires-Python"] == ">=3.11"
144
+ assert metadata["Requires-Python"] == _PROJECT["requires-python"]
145
145
  assert set(cast(list[str], metadata.get_all("Requires-Dist", []))) == _EXPECTED_REQUIRES_DIST
146
146
  assert "Development Status :: 3 - Alpha" in metadata.get_all("Classifier", [])
147
147
  assert "Typing :: Typed" in metadata.get_all("Classifier", [])