From dc8a630df36c17984dc31f669e38815892c878bd Mon Sep 17 00:00:00 2001 From: ykcheungab Date: Mon, 19 Oct 2026 20:56:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E5=B8=83=20SDK=200.6.0=20=E5=B9=B6?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=9C=BA=E6=A0=87=E5=AE=9A=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持不带前缀的版本标签,保留 Finger 资产随 wheel 交付。发布工具 97 项回归及 SDK 自带资产的场标定录像验证通过。 --- build/release/cli.py | 2 ++ build/release/github.py | 15 +++++++++++---- docs/field-gain-model.zh.md | 29 ++++++++++++++++++++++++++++- docs/publishing.en.md | 4 ++++ src/orisys/__init__.py | 2 +- tests/test_release_publish.py | 14 +++++++++++--- 6 files changed, 57 insertions(+), 9 deletions(-) diff --git a/build/release/cli.py b/build/release/cli.py index 239ac7e..d42a5e2 100644 --- a/build/release/cli.py +++ b/build/release/cli.py @@ -192,6 +192,7 @@ def _cmd_github(argv: list[str]) -> int: help="actually mutate the release repo, push, and create the release", ) parser.add_argument("--notes-file", type=Path, default=None, help="release notes markdown") + parser.add_argument("--tag", default=None, help="release tag: or v (default)") parser.add_argument( "--attach-preflight", action="store_true", @@ -218,6 +219,7 @@ def _cmd_github(argv: list[str]) -> int: version=args.version, apply=args.apply, notes_file=args.notes_file, + tag=args.tag, attach_preflight=args.attach_preflight, allow_dirty_release=args.allow_dirty_release, skip_fetch=args.skip_fetch, diff --git a/build/release/github.py b/build/release/github.py index f91bea2..4621de0 100644 --- a/build/release/github.py +++ b/build/release/github.py @@ -8,7 +8,7 @@ 3. sync the open-source subset of this checkout into ``orisys-sdk-release`` (``tools/sync_downstreams.py`` + the manifest's ``checks``) 4. stage ``SDK//*.whl`` into ``orisys-sdk-release/release//`` -5. commit, tag ``v``, push branch + tag +5. commit, tag (default ``v``), push branch + tag 6. create the GitHub Release with the wheels attached, then verify the assets Nothing mutates anything unless ``--apply`` is passed: the default is a dry run @@ -48,6 +48,7 @@ class Options: skip_fetch: bool = False skip_checks: bool = False skip_release_upload: bool = False + tag: str | None = None @dataclass @@ -131,7 +132,7 @@ def build_github_steps( tag, "--verify-tag", "--title", - title or f"v{version}", + title or tag, "--latest", ] if notes_file is not None: @@ -242,6 +243,10 @@ def _stage_wheels(wheels: list[Path], asset_dir: Path) -> None: def publish(options: Options) -> int: version = options.version + tag = options.tag or f"v{version}" + if tag not in {version, f"v{version}"}: + print(f"[FAIL] tag must be {version!r} or {'v' + version!r}") + return 1 mode = "APPLY" if options.apply else "DRY RUN" print(f"=== release github: orisys {version} ({mode}) ===") @@ -287,8 +292,10 @@ def publish(options: Options) -> int: return 1 print(f"[ok ] release repo: {repo} ({branch}) clean={not dirty}") - tag = f"v{version}" existing = _existing_release_tags(repo, version) + if existing and tag not in existing: + print(f"[FAIL] version already has tag(s) {existing}; refusing a second tag {tag}") + return 1 # A tag that exists without a GitHub Release means a previous run got as far # as pushing the tag and then failed (or the upload was left manual). That is # exactly the resumable state, so continue instead of refusing. @@ -383,7 +390,7 @@ def publish(options: Options) -> int: _git(repo, "add", "-A") pending = _git(repo, "status", "--porcelain") if pending: - _git(repo, "commit", "-m", f"release {version}") + _git(repo, "commit", "-m", f"发布 SDK {version}") print(f"[ok ] committed {len(pending.splitlines())} change(s) in {repo}") else: print("[ok ] nothing new to commit in the release repo") diff --git a/docs/field-gain-model.zh.md b/docs/field-gain-model.zh.md index 7e0539a..e2accee 100644 --- a/docs/field-gain-model.zh.md +++ b/docs/field-gain-model.zh.md @@ -8,10 +8,37 @@ ## 定位与边界 从现有多点增益生成空间图,对 HHD 无旋向量场做加权求和,作为 FN 的实验估计。 -不依赖深度、接触中心、最大光流点或单接触判定;实时入口尚未接入,必须显式拒绝。 +不依赖深度、接触中心、最大光流点或单接触判定。SDK 的 `FingerRuntime` 可直接加载模型、 +声明加权空载窗口并逐帧推断;处理来源可以是录像或相机。尚未接入的是 Studio 实时采集界面, +其应用入口仍显式拒绝场模型,不是 SDK 的来源限制。 现有增益对应各加载位置的整场响应,不是已验证的局部系数。交付证明软件契约与可复现估计, 不宣称局部压力、多接触力可加性或精度改善。负的基线差保留;显示阈值只由显示层决定。 +SDK 使用示例(配置、资产、模型和设备身份须匹配): + +```python +from orisys.finger import FingerRuntime + +runtime = FingerRuntime.open( + config="sensor.json", export_dir="assets", video="input.mp4", + cal_path="force_calibration.field.json", device_id="YOUR-SENSOR-SN", +) +try: + # 仅在传感器无载时声明;video 也可以传相机编号。 + runtime.declare_unloaded_reference("unloaded-1") + with runtime.pipeline(contact=False, include=()) as pipe: + while (snapshot := pipe.wait()) is not None: + if snapshot.calibration_status.get("fn") == "ok": + print(snapshot.normal_force) +finally: + runtime.close() +``` + +模型前 30 个有效处理帧用于建立零点;订阅者可能跳过中间快照,不能以收到的快照数判断就绪。 +运行中换模型必须由调用方在处理线程的帧边界执行,随后重新声明空载窗口;不能与运行中的 +pipeline 并发调用切换接口。当前独立验证覆盖录像的同步处理和 pipeline 软件链, +不等于已验证相机实机精度、吞吐或延迟。 + ## 文件字段 `model.type` 为 `field_gain/1`,`input_profile` 为 `hhd_normal_l1_field/1`,`outputs` 仅 `["fn"]`。 diff --git a/docs/publishing.en.md b/docs/publishing.en.md index 5a4b061..6322f2c 100644 --- a/docs/publishing.en.md +++ b/docs/publishing.en.md @@ -106,6 +106,10 @@ Release. See the launcher help and [build/README.md](../build/README.md) for the exact flags. A published version cannot be overwritten, so do not treat a rerun as a way to replace bad wheels. +GitHub tags default to `v`. Pass `--tag ` for a tag without the +prefix; both forms must match the certified version. Use `--notes-file ` +to publish reviewed release notes. + The release order is build all candidates, commit source changes, run the clean preflight, preview both publishers, then execute the authorized publications. GitHub attaches all certified wheels and generates notes naming their actual diff --git a/src/orisys/__init__.py b/src/orisys/__init__.py index 8466988..f221596 100644 --- a/src/orisys/__init__.py +++ b/src/orisys/__init__.py @@ -5,7 +5,7 @@ A Python library for processing and analyzing optical tactile sensor data, including image stitching, optical flow tracking, and deformation decomposition. """ -__version__ = "0.5.4" +__version__ = "0.6.0" __author__ = "Orisys" from . import calibration, capture, configs, finger, signal_processing, util diff --git a/tests/test_release_publish.py b/tests/test_release_publish.py index b4760f3..68678ce 100644 --- a/tests/test_release_publish.py +++ b/tests/test_release_publish.py @@ -338,7 +338,8 @@ def test_publish_dry_run_resumes_when_tag_already_exists(tmp_path, monkeypatch, assert "gh release create v1.2.3" in output -def test_publish_dry_run_creates_tag_when_absent(tmp_path, monkeypatch, capsys): +@pytest.mark.parametrize("tag", [None, "1.2.4"]) +def test_publish_dry_run_creates_tag_when_absent(tmp_path, monkeypatch, capsys, tag): sdk, release, wheel = _synthetic_publish_layout(tmp_path, "1.2.4", tag_exists=False) monkeypatch.setattr(github, "REPO_ROOT", sdk) monkeypatch.setattr(github, "MANIFEST_PATH", sdk / "tools" / "downstream_sync_manifest.json") @@ -346,11 +347,18 @@ def test_publish_dry_run_creates_tag_when_absent(tmp_path, monkeypatch, capsys): monkeypatch.setattr(github, "_release_exists", lambda repo, tag: False) exit_code = github.publish( - github.Options(version="1.2.4", apply=False, skip_fetch=True) + github.Options(version="1.2.4", apply=False, skip_fetch=True, tag=tag) ) output = capsys.readouterr().out assert exit_code == 0 - assert "git tag v1.2.4" in output + expected_tag = tag or "v1.2.4" + assert f"git tag {expected_tag}" in output + assert f"gh release create {expected_tag} --verify-tag --title {expected_tag}" in output + + +def test_publish_rejects_tag_for_another_version(capsys): + assert github.publish(github.Options(version="1.2.4", tag="1.2.5")) == 1 + assert "tag must be" in capsys.readouterr().out def test_publish_refuses_when_release_already_exists(tmp_path, monkeypatch, capsys):