diff --git a/headroom/_ort.py b/headroom/_ort.py index 4a77d847a..8f10cd7bd 100644 --- a/headroom/_ort.py +++ b/headroom/_ort.py @@ -40,15 +40,40 @@ import importlib.util import logging import os import sys +from importlib.metadata import PackageNotFoundError, version from pathlib import Path logger = logging.getLogger(__name__) _ENV_VAR = "ORT_DYLIB_PATH" +_MIN_RUST_ORT_API_VERSION = (1, 24) # Tri-state module cache: unset sentinel / resolved path / None (no pin). _UNSET = object() _pinned: object = _UNSET +_pinned_from_override = False + + +def _installed_ort_version() -> tuple[int, int] | None: + """Return the installed ONNX Runtime major/minor without importing it.""" + try: + raw = version("onnxruntime") + return tuple(int(part) for part in raw.split(".")[:2]) # type: ignore[return-value] + except (PackageNotFoundError, ValueError): + return None + + +def rust_ort_runtime_compatible() -> bool: + """Whether native Rust detection can safely initialize ORT C API 24. + + A caller-supplied ``ORT_DYLIB_PATH`` remains an explicit override: its + library may be newer than the separately installed Python package. The + auto-pinned package library, however, must advertise at least 1.24. + """ + if _pinned_from_override: + return True + installed = _installed_ort_version() + return installed is not None and installed >= _MIN_RUST_ORT_API_VERSION def ensure_ort_dylib_pinned() -> str | None: @@ -84,12 +109,24 @@ def _resolve_ort_native_library(capi_dir: Path) -> Path | None: def _resolve_and_pin() -> str | None: + global _pinned_from_override try: existing = os.environ.get(_ENV_VAR) if existing: + _pinned_from_override = True logger.debug("%s already set; respecting user override: %s", _ENV_VAR, existing) return existing + installed = _installed_ort_version() + if installed is not None and installed < _MIN_RUST_ORT_API_VERSION: + logger.warning( + "onnxruntime %d.%d exposes an older C API than Rust detection " + "requires (1.24+); leaving %s unset and using Python detection", + *installed, + _ENV_VAR, + ) + return None + spec = importlib.util.find_spec("onnxruntime") if spec is None or not spec.origin: logger.debug( diff --git a/headroom/transforms/content_router.py b/headroom/transforms/content_router.py index a2a0f68ea..fd0704067 100644 --- a/headroom/transforms/content_router.py +++ b/headroom/transforms/content_router.py @@ -940,6 +940,20 @@ def _detect_content(content: str) -> DetectionResult: # another stuck daemon thread, so route straight to pure-Python. return _regex_detect_content_type(content) + # fastembed enables ort's API-24 feature. Entering the native initializer + # with an older pip ONNX Runtime does not raise: ort recursively re-enters + # its OnceLock error path and parks forever (#2960). Preflight before the + # extension call so supported Python 3.10 installs degrade immediately. + from headroom._ort import rust_ort_runtime_compatible + + if not rust_ort_runtime_compatible(): + _detect_native_unhealthy = True + logger.warning( + "Native content detection requires ONNX Runtime 1.24+; " + "using pure-Python detection for this process." + ) + return _regex_detect_content_type(content) + from headroom._core import detect_content_type as _rust_detect try: diff --git a/pyproject.toml b/pyproject.toml index 37463e191..e36dca4ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,7 +84,11 @@ proxy = [ "magika>=0.6.0", # ML content detection for ContentRouter "zstandard>=0.20.0", # Decompress zstd request bodies (Codex, etc.) "websockets>=13.0", # WebSocket proxy for /v1/responses (Codex gpt-5.4+) - "onnxruntime>=1.16.0", # Kompress ONNX INT8 text compression (no torch needed) + # Rust fastembed enables ORT C API 24. ORT <1.24 deadlocks instead of + # returning an initialization error; 1.24+ no longer ships Python 3.10 + # wheels, so 3.10 keeps Python-only ORT and bypasses native detection. + "onnxruntime>=1.24.0; python_version>='3.11'", + "onnxruntime>=1.16.0,<1.24.0; python_version<'3.11'", "transformers>=5.5.0,<6.0", # Tokenizer only (for Kompress) "watchdog>=4.0.0", # File watcher for live code graph reindexing (--code-graph) "sqlite-vec>=0.1.6", # Vector index for memory (--memory). Lightweight, no torch. @@ -234,7 +238,8 @@ mcp = [ ] # Voice filler detection voice = [ - "onnxruntime>=1.16.0", + "onnxruntime>=1.24.0; python_version>='3.11'", + "onnxruntime>=1.16.0,<1.24.0; python_version<'3.11'", "transformers>=5.5.0,<6.0", "torch>=2.12.1; sys_platform != 'darwin' or platform_machine != 'x86_64'", ] diff --git a/tests/test_onnx_dependency_contract.py b/tests/test_onnx_dependency_contract.py new file mode 100644 index 000000000..03c95cfa8 --- /dev/null +++ b/tests/test_onnx_dependency_contract.py @@ -0,0 +1,35 @@ +"""Dependency contract between Rust ort API 24 and pip ONNX Runtime.""" + +from __future__ import annotations + +from pathlib import Path + +import tomllib +from packaging.requirements import Requirement + +ROOT = Path(__file__).resolve().parents[1] + + +def test_shipping_ort_dependencies_require_api24_where_wheels_exist() -> None: + project = tomllib.loads((ROOT / "pyproject.toml").read_text())["project"] + optional = project["optional-dependencies"] + + for extra in ("proxy", "voice"): + requirements = [ + Requirement(value) + for value in optional[extra] + if Requirement(value).name == "onnxruntime" + ] + assert len(requirements) == 2 + modern = next( + req + for req in requirements + if req.marker and req.marker.evaluate({"python_version": "3.11"}) + ) + legacy = next( + req + for req in requirements + if req.marker and req.marker.evaluate({"python_version": "3.10"}) + ) + assert modern.specifier.contains("1.24.0") + assert not legacy.specifier.contains("1.24.0") diff --git a/tests/test_transforms/test_detect_fallback_1123.py b/tests/test_transforms/test_detect_fallback_1123.py index d9d0623eb..aa6b0036e 100644 --- a/tests/test_transforms/test_detect_fallback_1123.py +++ b/tests/test_transforms/test_detect_fallback_1123.py @@ -5,6 +5,9 @@ from __future__ import annotations import asyncio +import pytest + +import headroom._ort as ort_runtime from headroom.transforms import content_router as cr # Patch the native detector via its string target ("headroom._core.detect_content_type") @@ -15,6 +18,12 @@ from headroom.transforms import content_router as cr # the control-flow tests would silently run the real detector and never see the exception. +@pytest.fixture(autouse=True) +def _compatible_mock_native_runtime(monkeypatch: pytest.MonkeyPatch) -> None: + """These tests replace the native detector, so keep the ORT preflight open.""" + monkeypatch.setattr(ort_runtime, "rust_ort_runtime_compatible", lambda: True) + + def test_falls_back_on_rust_exception(monkeypatch): """An ordinary exception from the native detector degrades to regex.""" @@ -58,8 +67,6 @@ def test_control_flow_exceptions_propagate(monkeypatch): monkeypatch.setattr("headroom._core.detect_content_type", _interrupt) monkeypatch.setattr(cr, "_detect_panic_warned", False, raising=False) - import pytest - with pytest.raises(KeyboardInterrupt): cr._detect_content("content") @@ -74,7 +81,5 @@ def test_cancelled_error_propagates(monkeypatch): monkeypatch.setattr("headroom._core.detect_content_type", _cancel) monkeypatch.setattr(cr, "_detect_panic_warned", False, raising=False) - import pytest - with pytest.raises(asyncio.CancelledError): cr._detect_content("content") diff --git a/tests/test_transforms/test_ort_dylib.py b/tests/test_transforms/test_ort_dylib.py index a10cdd2c6..405db1df2 100644 --- a/tests/test_transforms/test_ort_dylib.py +++ b/tests/test_transforms/test_ort_dylib.py @@ -22,6 +22,8 @@ import headroom._ort as _ort def _fresh_resolver(monkeypatch): """Reset the module-level cache and scrub the env before every test.""" monkeypatch.setattr(_ort, "_pinned", _ort._UNSET) + monkeypatch.setattr(_ort, "_pinned_from_override", False) + monkeypatch.setattr(_ort, "_installed_ort_version", lambda: (1, 24)) monkeypatch.delenv("ORT_DYLIB_PATH", raising=False) @@ -70,6 +72,34 @@ def test_respects_existing_env(monkeypatch): monkeypatch.setenv("ORT_DYLIB_PATH", r"C:\custom\onnxruntime.dll") assert _ort.ensure_ort_dylib_pinned() == r"C:\custom\onnxruntime.dll" assert _ort.os.environ["ORT_DYLIB_PATH"] == r"C:\custom\onnxruntime.dll" + assert _ort.rust_ort_runtime_compatible() + + +def test_incompatible_package_is_not_pinned(monkeypatch, tmp_path, caplog): + monkeypatch.setattr(_ort, "_installed_ort_version", lambda: (1, 23)) + pkg = tmp_path / "onnxruntime" + capi = pkg / "capi" + capi.mkdir(parents=True) + (capi / "libonnxruntime.so.1.23.2").write_bytes(b"old") + _fake_spec_for(monkeypatch, pkg) + + assert _ort.ensure_ort_dylib_pinned() is None + assert not _ort.rust_ort_runtime_compatible() + assert "older C API" in caplog.text + + +def test_content_router_bypasses_native_detector_for_incompatible_ort(monkeypatch, caplog): + import headroom.transforms.content_router as router + + monkeypatch.setenv("HEADROOM_DETECT_BACKEND", "rust") + monkeypatch.setattr(_ort, "rust_ort_runtime_compatible", lambda: False) + monkeypatch.setattr(router, "_detect_native_unhealthy", False) + + result = router._detect_content('{"safe": true}') + + assert result.content_type.value.startswith("json") + assert router._detect_native_unhealthy is True + assert "requires ONNX Runtime 1.24+" in caplog.text def test_pins_to_package_capi_dll(monkeypatch, tmp_path): diff --git a/tests/test_transforms_content_router.py b/tests/test_transforms_content_router.py index 89f18daa2..aeaf48aaf 100644 --- a/tests/test_transforms_content_router.py +++ b/tests/test_transforms_content_router.py @@ -5,6 +5,7 @@ from types import SimpleNamespace import pytest +import headroom._ort as ort_runtime import headroom.transforms.content_router as content_router_module from headroom.transforms.content_detector import ContentType, DetectionResult from headroom.transforms.content_router import ( @@ -35,6 +36,11 @@ def _reset_detect_module_state(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(content_router_module, "_detect_native_unhealthy", False) monkeypatch.setattr(content_router_module, "_detect_backend_warned", False) monkeypatch.setattr(content_router_module, "_detect_panic_warned", False) + # Router unit tests replace ``headroom._core.detect_content_type`` with + # deterministic fakes. Keep the separate ORT API-compatibility preflight + # open so those fakes reach the watchdog/circuit-breaker behavior under + # test; incompatibility itself is covered in test_ort_dylib.py (#2960). + monkeypatch.setattr(ort_runtime, "rust_ort_runtime_compatible", lambda: True) def test_compression_cache_handles_hits_skips_evictions_and_clear( diff --git a/uv.lock b/uv.lock index 2983d3c31..edd0b3646 100644 --- a/uv.lock +++ b/uv.lock @@ -756,8 +756,8 @@ dependencies = [ { name = "mmh3" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "opentelemetry-api" }, { name = "opentelemetry-exporter-otlp-proto-grpc" }, { name = "opentelemetry-sdk" }, @@ -1253,8 +1253,8 @@ dependencies = [ { name = "mmh3" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "pillow" }, { name = "py-rust-stemmers" }, { name = "requests" }, @@ -1699,8 +1699,8 @@ all = [ { name = "mcp" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "openai" }, { name = "openpyxl" }, { name = "opentelemetry-exporter-otlp-proto-http" }, @@ -1783,8 +1783,7 @@ html = [ { name = "trafilatura" }, ] image = [ - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version == '3.13.*'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.13'" }, { name = "pillow" }, { name = "rapidocr", marker = "python_full_version >= '3.13'" }, { name = "rapidocr-onnxruntime", marker = "python_full_version < '3.13'" }, @@ -1823,8 +1822,8 @@ proxy = [ { name = "httpx", extra = ["http2"] }, { name = "magika" }, { name = "mcp" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "openai" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, { name = "sqlite-vec" }, @@ -1840,8 +1839,8 @@ proxy-prod = [ { name = "httpx", extra = ["http2"] }, { name = "magika" }, { name = "mcp" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "openai" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, { name = "sqlite-vec" }, @@ -1872,8 +1871,8 @@ sandbox = [ { name = "mcp" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "openai" }, { name = "openpyxl" }, { name = "opentelemetry-exporter-otlp-proto-http" }, @@ -1902,16 +1901,16 @@ vector = [ { name = "hnswlib" }, ] voice = [ - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "torch", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, { name = "transformers" }, ] voice-train = [ { name = "accelerate" }, { name = "datasets" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "torch", marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, { name = "transformers" }, ] @@ -1961,9 +1960,11 @@ requires-dist = [ { name = "numpy", marker = "extra == 'evals'", specifier = ">=1.24.0" }, { name = "numpy", marker = "extra == 'relevance'", specifier = ">=1.24.0" }, { name = "ollama", marker = "extra == 'dev'", specifier = ">=0.4.0" }, + { name = "onnxruntime", marker = "python_full_version >= '3.11' and extra == 'proxy'", specifier = ">=1.24.0" }, + { name = "onnxruntime", marker = "python_full_version >= '3.11' and extra == 'voice'", specifier = ">=1.24.0" }, + { name = "onnxruntime", marker = "python_full_version < '3.11' and extra == 'proxy'", specifier = ">=1.16.0,<1.24.0" }, + { name = "onnxruntime", marker = "python_full_version < '3.11' and extra == 'voice'", specifier = ">=1.16.0,<1.24.0" }, { name = "onnxruntime", marker = "python_full_version >= '3.13' and extra == 'image'", specifier = ">=1.7,<2" }, - { name = "onnxruntime", marker = "extra == 'proxy'", specifier = ">=1.16.0" }, - { name = "onnxruntime", marker = "extra == 'voice'", specifier = ">=1.16.0" }, { name = "openai", marker = "extra == 'dev'", specifier = ">=1.0.0" }, { name = "openai", marker = "extra == 'evals'", specifier = ">=1.0.0" }, { name = "openai", marker = "extra == 'proxy'", specifier = ">=2.14.0" }, @@ -2863,8 +2864,8 @@ dependencies = [ { name = "click" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.14'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.14'" }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11'" }, { name = "python-dotenv" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fe/b6/8fdd991142ad3e037179a494b153f463024e5a211ef3ad948b955c26b4de/magika-0.6.2.tar.gz", hash = "sha256:37eb6ae8020f6e68f231bc06052c0a0cbe8e6fa27492db345e8dc867dbceb067", size = 3036634, upload-time = "2025-05-02T14:54:18.88Z" } @@ -3769,22 +3770,12 @@ name = "onnxruntime" version = "1.23.2" source = { registry = "https://pypi.org/simple/" } resolution-markers = [ - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version < '3.11'", ] dependencies = [ { name = "coloredlogs" }, { name = "flatbuffers" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11' or python_full_version >= '3.14'" }, - { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11' and python_full_version < '3.14'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" } }, { name = "packaging" }, { name = "protobuf" }, { name = "sympy" }, @@ -3822,6 +3813,15 @@ resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", "python_full_version >= '3.14' and sys_platform == 'emscripten'", "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.11.*' and sys_platform == 'win32'", + "python_full_version == '3.11.*' and sys_platform == 'emscripten'", + "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ { name = "flatbuffers" }, @@ -5416,7 +5416,8 @@ source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" }, { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" }, - { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" } }, + { name = "onnxruntime", version = "1.23.2", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" }, + { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple/" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" }, { name = "opencv-python" }, { name = "pillow" }, { name = "pyclipper" },