Skip to content

Conversation

@zephyr-sh
Copy link
Contributor

@zephyr-sh zephyr-sh commented Jan 10, 2026

1) 本次 PR 的目標(Overview)

  • 目標:將 pytest 測試覆蓋率提升到 99%,並把「覆蓋率/靜態檢查/格式」變成可自動驗收的守門機制。
  • 導入靜態與格式檢查(品質門檻):
    • ruff check
    • ruff format --check
    • pyright
  • 優化安裝流程,解耦重型模組依賴:
    • 將推論後端改為 opt-in extraspip install . 保持輕量;需要推論才安裝對應 extra)
    • 避免在「僅使用工具函式/結構」的情境下被迫安裝 ORT/OpenVINO/Torch
  • 推論後端支援擴充:
    • 原本僅支援 ORT(ONNX Runtime)
    • 本次新增支援 OpenVINOTorchScript
    • 透過 capybara/runtime.py 提供 runtime/backends 的統一選擇與 auto-detect 能力
  • 為什麼現在需要這些守門機制:
    • 本次改動把「推論後端」從單一 ORT 擴展到多後端(OpenVINO/TorchScript),且引入可選依賴與更多輸入型態/邊界情境;若沒有自動化檢核,回歸風險會顯著上升。
    • ruff/pyright/coverage gate 讓「程式風格、型別契約、邊界行為」能在 CI 直接被擋下,降低維運時的隱性 bug(silent failure)與環境相依問題。

可驗收指令清單

# 1) 單元測試 + Coverage(本 PR 定義的 coverage 規則由 .coveragerc 控制)
python -m pytest --cov=capybara --cov-config=.coveragerc --cov-report=term --cov-report=xml

# 2) Lint
ruff check .

# 3) Format(僅檢查,不改檔)
ruff format --check .

# 4) Type checking
pyright

(可選)安裝推論後端:pip install -e '.[onnxruntime]' / pip install -e '.[openvino]' / pip install -e '.[torchscript]' / pip install -e '.[all]'

2) 測試策略與覆蓋率(Testing & Coverage)

  • 測試新增/強化範圍(摘要):
    • 推論後端抽象層與引擎封裝:ONNX(Open ORT stub)、OpenVINO(stub)、TorchScript(torch stub) 的初始化、輸入/輸出契約、benchmark 參數驗證、非預期輸入型態處理。
    • 核心資料結構:Box/BoxesKeypoints/KeypointsListPolygon/Polygons 的轉換、正規化/反正規化、拼接與例外輸入。
    • 影像/幾何處理:padding/rotate 的 dtype/通道邊界、imresize 比例回傳、透視變換的寬高交換邏輯。
    • 工具與 IO:get_filesdownload_from_googleTimerTqdm 的錯誤處理與邊界條件(空輸入、無效參數、串流失敗等)。
    • 視覺化繪圖:字型缺失 fallback、draw_line 退化情境(零長度/無效 gap)、mask normalization 的除零保護、色盤生成與 lazy import。
  • 本次特別覆蓋的風險類型:
    • 輸入驗證(型別/維度/參數範圍)、邊界條件(空資料、零長度、無效 fps)、例外處理(optional dependency 不存在、串流失敗)、IO 錯誤、以及「silent failure」型錯誤(正規化座標旗標遺失導致結果默默錯)。
  • 針對既有 bug 的補測試原則:以 tests/test_hidden_bugs_regressions.py 與各模組新增測試為主,採「先寫測試重現,再修 code」避免回歸。

Coverage 數字(可重現)

  • 變更前(main@0b2c034;CPU 環境需避開 GPU-only 測試檔):
    • 指令:python -m pytest --ignore tests/onnxruntime/test_engine_io_binding.py --cov=capybara --cov-config=.coveragerc --cov-report=term
    • 結果:TOTAL 63%(多數核心模組覆蓋率偏低,例如 capybara/vision/visualization/draw.py 僅 15%)
  • 變更後(本 PR):
    • 指令:python -m pytest --cov=capybara --cov-config=.coveragerc --cov-report=term
    • 結果:493 passedTOTAL 99%3419 stmts, 1 miss;主要模組多為 100%)
    • 覆蓋率提升主要來源:capybara/vision/visualization/draw.pycapybara/utils/*capybara/onnxengine/*、以及新增的 capybara/runtime.pycapybara/openvinoengine/*capybara/torchengine/* 的完整測試覆蓋。

3) 修復錯誤程式碼(Bug Fixes)

修復主題 1:正規化座標旗標遺失,導致視覺化/座標運算默默錯(silent failure)

(a) 原本寫法會導致的錯誤

  • 錯誤類型:資料不一致 / silent failure(is_normalizedconvert()/copy() 或 prepare helper 中被丟失)。
  • 影響面:
    • Box/Polygon/Keypoints 等結構在「正規化座標」情境(0~1)被當成「絕對座標」使用,繪圖會落在角落、裁切/座標換算錯誤但不一定拋例外。
    • clip() 先轉到 XYXY 再回傳時,模式標記可能與資料不一致(例如輸入 XYWH 卻回傳一組 XYXY 值但標成 XYWH)。

(b) 重現錯誤的方法

  • Pytest:
    • tests/vision/visualization/test_draw.py::test_draw_box_denormalizes_normalized_box
    • tests/structures/test_boxes.py::test_box_convert_preserves_is_normalized_flag
    • tests/structures/test_boxes.py::test_box_clip_preserves_box_mode_for_xywh_inputs

(c) 怎麼修,以及為什麼這樣修

  • 修改前 → 修改後(關鍵差異):
    • convert()/copy()/shift()/square()/clip() 等回傳新物件時,改為保留 is_normalized,避免語意被默默重置。
    • clip() 改為「先轉 XYXY 做 clipping → 再 convert 回原本 box_mode」,確保資料與 mode 標記一致。
    • 視覺化輸入前置處理(prepare_keypoints/prepare_polygon/...)對已是結構物件的輸入不再重建,避免把旗標洗掉。
  • 為何能消除根因:
    • 根因是「建立新物件時未帶入狀態(flag)/回傳資料格式與標記不一致」;修正後由資料結構層保證不變量(invariant)。
  • 替代方案:
    • 可改成所有結構一律以某個 mode 作內部儲存(例如一律存 XYXY),但牽涉大規模重構與 API 行為變更;本次採最小改動修正根因。
  • 對應回歸測試:同 (b)。

修復主題 2:pyproject.tomlonnxruntime-gpu extra 名稱錯誤,導致安裝失敗

(a) 原本寫法會導致的錯誤

  • 錯誤類型:安裝流程錯誤(pip install -e '.[onnxruntime-gpu]' 會因套件名寫成 onnxruntime_gpu 而失敗)。
  • 影響面:使用者/CI 無法透過 extra 正確安裝 GPU 版 ORT。

(b) 重現錯誤的方法

  • Pytest:tests/test_hidden_bugs_regressions.py::test_pyproject_onnxruntime_gpu_extra_uses_hyphenated_package_name

(c) 怎麼修,以及為什麼這樣修

  • 修改前 → 修改後:將錯誤的 onnxruntime_gpu 修正為 PyPI 正確名稱 onnxruntime-gpu
  • 根因:套件名稱(hyphen vs underscore)誤用。
  • 對應回歸測試:同 (b)。

修復主題 3:檔案/下載工具在邊界條件下行為不正確(目錄誤入結果、下載頁面 token 解析失敗)

(a) 原本寫法會導致的錯誤

  • 錯誤類型:
    • get_files(..., suffix=None) 可能把「資料夾」也當成結果回傳(資料型態不符合預期)。
    • Google Drive 下載流程遇到確認頁/HTML form/串流錯誤時可能失敗或拋出難以診斷的例外。
  • 影響面:上游程式假設回傳都是檔案路徑/下載成功時,容易造成後續 IO 錯誤或 silent failure。

(b) 重現錯誤的方法

  • Pytest:
    • tests/test_hidden_bugs_regressions.py::test_get_files_does_not_return_directories_when_suffix_none
    • tests/utils/test_download_from_google.py(多案例涵蓋 token / HTML form / 串流失敗)

(c) 怎麼修,以及為什麼這樣修

  • 修改前 → 修改後:
    • get_files 在收集時先過濾 Path.is_file(),確保結果語意一致。
    • download_from_google 增強:cookie confirm token、HTML form action/hidden inputs、confirm= 字串 fallback;串流例外統一包裝成可讀的 RuntimeError
  • 根因:
    • 缺少「輸出不變量」與「Google Drive 多種下載回應」的處理分支。
  • 對應回歸測試:同 (b)。

修復主題 4:影像/幾何處理對通道數、dtype、參數邊界處理不足

(a) 原本寫法會導致的錯誤

  • 錯誤類型:資料不一致 / 邊界條件 bug
    • RGBA(4 通道)在 pad/imrotate 的 constant value 可能只填到部分通道。
    • imresize(return_scale=True) 在單邊指定尺寸時回傳 scale 的分支未被驗證。
    • 參數或輸入維度不合法時若未明確 raise,容易造成不可預期行為。
  • 影響面:影像處理結果產生錯誤邊框、dtype 變化或在錯誤輸入時行為不明確。

(b) 重現錯誤的方法

  • Pytest(節選):
    • tests/test_hidden_bugs_regressions.py::test_pad_constant_value_fills_all_channels_for_rgba
    • tests/test_hidden_bugs_regressions.py::test_imrotate_constant_border_fills_all_channels_for_rgba
    • tests/test_hidden_bugs_regressions.py::test_imrotate_preserves_dtype_for_float32_inputs
    • tests/vision/test_functional.py::test_pad_rejects_invalid_pad_value_type_and_invalid_image_ndim
    • tests/vision/test_geometric.py::test_imresize_return_scale_when_only_one_dim_provided
    • tests/vision/test_geometric.py::test_imrotate_validates_image_ndim_and_border_value_tuple_sizes

(c) 怎麼修,以及為什麼這樣修

  • 修改前 → 修改後:
    • 依照影像通道數自動展開 scalar pad_value/bordervalue,並在 tuple 長度不匹配時明確 raise。
    • 補齊 input validation(維度/參數範圍)並以測試鎖定行為。
  • 根因:未對多通道與非法輸入建立明確契約。
  • 對應回歸測試:同 (b)。

修復主題 5:視覺化繪圖在字型缺失、退化輸入與 normalization 下不穩定

(a) 原本寫法會導致的錯誤

  • 錯誤類型:例外處理不足 / 除零風險 / 輸入驗證不足
    • 字型檔不存在時 draw_text 可能失敗;某些 font 物件不支援 getbbox 可能導致例外。
    • draw_linegap<=0pt1==pt2 的退化情境行為不明確。
    • draw_mask(min_max_normalize=True) 在 mask 全常數時有除零風險。
  • 影響面:可視化工具在缺字型/極端輸入下崩潰或產生錯誤結果。

(b) 重現錯誤的方法

  • Pytest(節選):
    • tests/test_hidden_bugs_regressions.py::test_draw_text_falls_back_when_font_files_missing
    • tests/vision/visualization/test_draw.py::test_draw_text_handles_fonts_without_getbbox
    • tests/test_hidden_bugs_regressions.py::test_draw_line_handles_zero_length_and_validates_gap
    • tests/test_hidden_bugs_regressions.py::test_draw_mask_minmax_normalize_constant_mask_is_safe
    • tests/vision/visualization/test_draw.py::test_generate_colors_and_distinct_color

(c) 怎麼修,以及為什麼這樣修

  • 修改前 → 修改後:
    • 字型載入改成多候選路徑 + load_default() fallback;getbbox 失敗則安全降級(offset=0)。
    • draw_line 明確驗證 gap>0,並處理零長度線段為點狀繪製。
    • draw_mask 在 denom=0 時輸出全 0 mask,避免除零。
  • 根因:缺少「可視化工具在不完整環境」的防禦性設計。
  • 對應回歸測試:同 (b)。

修復主題 6:推論引擎封裝缺少一致的輸入/輸出契約與可測性(並擴充 OpenVINO/TorchScript)

(a) 原本寫法會導致的錯誤

  • 錯誤類型:輸入契約不清/環境相依(GPU/CUDA library)/回歸風險高
    • GPU-only 測試在非 CUDA 環境可能不穩定(例如 CUDA provider 初始化失敗但測試未被 skip)。
    • 引擎缺少一致的 feed 驗證、輸出命名一致性、benchmark 參數驗證等守門邏輯。
  • 影響面:CI/使用者環境差異導致測試失敗或推論行為不一致。

(b) 重現錯誤的方法

  • Pytest:
    • 本次新增(stubbed/可在無實體依賴下跑):
      • tests/onnxengine/test_engine_stubbed.py
      • tests/openvinoengine/test_openvino_engine_stubbed.py
      • tests/test_torchengine.py
    • 變更前的環境相依例:tests/onnxruntime/test_engine_io_binding.py 在缺少 CUDA runtime 時可能不穩定(本 PR 以 stub 測試取代此類依賴)。

(c) 怎麼修,以及為什麼這樣修

  • 修改前 → 修改後:
    • 建立 capybara/runtime.py 的 Runtime/Backend registry 與 auto backend 策略,並提供 capybara/onnxenginecapybara/openvinoenginecapybara/torchengine 的一致封裝介面(run/summary/benchmark)。
    • 對 feed/input/output schema 與 benchmark 參數做明確驗證,避免 silent mislabeling 或不合理的 benchmark 設定。
    • 測試改採 stubbed runtime(fake onnxruntime/fake openvino/fake torch),提高可測性與環境可重現性。
  • 根因:
    • 推論後端多樣化後,若沒有「一致的 API 契約 + 可重現測試」,維運與回歸成本會急遽上升。
  • 對應回歸測試:同 (b)。

4) 工具與品質門檻(Quality Gates)

  • 新增/調整的專案設定:
    • pyproject.toml:加入 ruff 設定(lint/format)、並用 optional-dependencies 提供推論後端 extras(onnxruntime/openvino/torchscript)。
    • pyrightconfig.json:啟用 typeCheckingMode=basic,並納入 capybaratests
    • .coveragerc:定義 coverage 規則(排除平台/環境相依或非核心模組,讓 coverage gate 聚焦在可測且需維護的核心程式碼)。
    • .github/workflows/ci.yml:CI 增加 pyright,並將 coverage gate 設為 行覆蓋率 >= 99% 且強制執行
  • 合併前必須通過(本地/CI 一致):
    • ruff check .
    • ruff format --check .
    • pyright
    • python -m pytest --cov=capybara --cov-config=.coveragerc --cov-report=term
  • 已知限制/暫不納入範圍(並明確理由):
    • .coveragerc omit:capybara/cpuinfo.pycapybara/utils/system_info.pycapybara/vision/ipcam/app.py
      • 理由:平台/環境相依或屬於 optional feature(例如 Flask app),不應阻擋核心庫的 coverage gate;核心邏輯仍可由對應模組測試覆蓋。
    • pyrightconfig.json exclude:capybara/cpuinfo.py
      • 理由:該模組大量動態/平台分支,短期內不適合納入 basic type checking gate;其餘核心模組已納入。

5) 風險與相容性(Risk & Compatibility)

  • 可能的行為變化:
    • 多數函式新增更嚴格的輸入驗證(例如 pad/imrotate/draw_line 的參數檢查);以往可能「默默接受」的輸入,現在會 raise ValueError/TypeError
    • Box/Boxesclip/convert/copy 等操作現在會保留 is_normalized,並保證回傳資料與 box_mode 一致;若既有呼叫端依賴舊的錯誤行為,需調整。
  • 回溯相容性 / breaking change:
    • 套件安裝改以 pyproject.toml 為主(移除 setup.py),且推論後端改為 opt-in extras;若既有流程依賴 setup.py 或預設就有 ORT/OpenVINO/Torch,需改用 extras 安裝。
    • 舊有 ORT 專用/環境相依測試(尤其 GPU-only)已由更可重現的 stubbed 測試取代;若 downstream 依賴該測試檔/路徑,需同步更新。
  • Migration notes(建議):
    • 推論後端安裝請改用:
      • ORT:pip install -e '.[onnxruntime]'pip install -e '.[onnxruntime-gpu]'
      • OpenVINO:pip install -e '.[openvino]'
      • TorchScript:pip install -e '.[torchscript]'
    • 建議在 CI/本地固定使用本 PR 的驗收指令(見 Overview),確保格式/型別/測試/覆蓋率一致。

@zephyr-sh zephyr-sh force-pushed the prepare_update_to_version_1-0-0 branch 2 times, most recently from 6527870 to 8f48254 Compare January 10, 2026 02:36
@zephyr-sh zephyr-sh force-pushed the prepare_update_to_version_1-0-0 branch from 8f48254 to 6ad06d8 Compare January 10, 2026 02:50
@zephyr-sh zephyr-sh self-assigned this Jan 10, 2026
@zephyr-sh zephyr-sh changed the title feat: Add Pytest summary generation script and CI workflow Prepare for v1.0.0 release Jan 10, 2026
@DocsaidLab DocsaidLab deleted a comment from github-actions bot Jan 10, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 10, 2026

CI 概覽

項目 狀態
Ruff Lint ✅ 通過
Ruff Format ✅ 通過
Pytest ✅ 通過 (exit=0)
Coverage 行 99.97% / 分支 0%(門檻 行 99% / 分支 0%) → ✅
Coverage Gate ✅ 通過

快速連結

  • Workflow 執行
  • 測試 HTML:不可用
  • JUnit XML:不可用
  • Coverage HTML:不可用

Pytest 結果

  • 狀態: ✅ 通過 (exit=0)

測試環境

  • platform linux -- Python 3.10.19, pytest-9.0.2, pluggy-1.6.0 -- /home/shayne/actions-runner/_work/_tool/Python/3.10.19/x64/bin/python
  • rootdir: /home/shayne/actions-runner/_work/Capybara/Capybara
  • plugins: html-4.1.1, metadata-3.1.1, cov-7.0.0
  • 測試統計: 共 493; ✅ 通過 493; ❌ 失敗 0; ⚠️ 錯誤 0; ⏭️ 跳過 0; 耗時 3.622 秒

最慢測試 Top 20

測試 耗時 (秒)
tests.vision.videotools.test_video2frames_v2.test_video2frames_v2 0.406
tests.test_hidden_bugs_regressions.test_visualization_package_import_is_lazy 0.203
tests.vision.videotools.test_video2frames.test_video2frames_with_fps_greater_than_video_fps 0.164
tests.vision.videotools.test_video2frames.test_video2frames 0.096
tests.vision.videotools.test_video2frames_v2.test_video2frames_v2_with_fps 0.035
tests.vision.ipcam.test_camera.test_ipcam_capture_is_an_iterator_and_yields_frames 0.034
tests.vision.videotools.test_video2frames.test_video2frames_with_fps 0.033
tests.vision.visualization.test_draw.test_draw_detection_and_draw_detections_end_to_end 0.023
tests.openvinoengine.test_openvino_engine_stubbed.test_openvino_async_queue_requires_asyncinferqueue 0.021
tests.vision.visualization.test_draw.test_draw_text_draws_pixels 0.008
tests.openvinoengine.test_openvino_engine_stubbed.test_openvino_engine_runs_with_stub 0.005
tests.vision.videotools.test_video2frames.test_video2frames_rejects_non_positive_fps 0.005
tests.test_hidden_bugs_regressions.test_draw_text_falls_back_when_font_files_missing 0.004
tests.vision.test_functional.test_meanblur 0.003
tests.vision.test_improc.test_imread 0.003
tests.onnxengine.test_engine_stubbed.test_onnx_engine_with_stubbed_runtime 0.002
tests.onnxengine.test_engine_stubbed.test_onnx_engine_benchmark_validates_repeat_and_warmup 0.002
tests.onnxengine.test_engine_stubbed.test_onnx_engine_iobinding_without_run_options 0.002
tests.onnxengine.test_engine_stubbed.test_onnx_engine_extract_metadata_parses_json 0.002
tests.onnxengine.test_engine_stubbed.test_onnx_engine_missing_required_input_raises_keyerror 0.002

覆蓋率

  • 總覆蓋率: 行 99.97% (3418/3419), 分支 0% (0/0)

覆蓋率最低的檔案 (前 10 名)

檔案 行覆蓋 分支覆蓋
vision/geometric.py 98.80% 0%
__init__.py 100% 0%
enums.py 100% 0%
mixins.py 100% 0%
runtime.py 100% 0%
typing.py 100% 0%
onnxengine/__init__.py 100% 0%
onnxengine/engine.py 100% 0%
onnxengine/metadata.py 100% 0%
onnxengine/utils.py 100% 0%

覆蓋率缺口

未覆蓋的檔案列表
Name                           Stmts   Miss  Cover   Missing
------------------------------------------------------------
capybara/vision/geometric.py      83      1    99%   252
------------------------------------------------------------
TOTAL                           3419      1    99%
37 files skipped due to complete coverage.
  • 產物: 不可用

@zephyr-sh zephyr-sh added bug Something isn't working enhancement New feature or request labels Jan 10, 2026
@kunkunlin1221
Copy link
Collaborator

Readme 沒有改?

- Updated README_tw.md to correct PyPI package name from `capybara_docsaid` to `capybara-docsaid` and improved installation instructions.
- Enhanced the Dockerfile to streamline the installation process by directly installing the package without building a wheel, reducing complexity.
@zephyr-sh
Copy link
Contributor Author

補上了。

Copy link
Collaborator

@kunkunlin1221 kunkunlin1221 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zephyr-sh zephyr-sh merged commit cf06518 into main Jan 13, 2026
1 check passed
@zephyr-sh zephyr-sh deleted the prepare_update_to_version_1-0-0 branch January 13, 2026 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants