diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index 6fd0cd34..8ab4d8d1 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -12,7 +12,6 @@ parameters: default: false - name: flcWheelsDir type: string - default: '' displayName: 'Path to directory containing the FLC wheels (for overriding foundry-local-core)' - name: outputDir type: string @@ -111,16 +110,23 @@ steps: Write-Warning "No FLC wheel found matching $filter in ${{ parameters.flcWheelsDir }}" } +- script: pip install onnxruntime-core==1.24.3 onnxruntime-genai-core==0.12.1 + displayName: 'Install ORT native packages' + +- script: pip install "pydantic>=2.0.0" "requests>=2.32.4" "openai>=2.24.0" + displayName: 'Install pure python dependencies' + # Build wheel — standard or WinML variant -# skip-native-deps=true omits foundry-local-core/onnxruntime pinned versions -# from the wheel metadata, since the pipeline pre-installs its own builds. +# The wheel retains all dependencies in its metadata so end users get +# native packages installed automatically. CI uses --no-deps to avoid +# re-downloading packages that were pre-installed from pipeline builds. - ${{ if eq(parameters.isWinML, true) }}: - - script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ + - script: python -m build --wheel -C winml=true --outdir dist/ displayName: 'Build wheel (WinML)' workingDirectory: $(repoRoot)/sdk/python - ${{ else }}: - - script: python -m build --wheel -C skip-native-deps=true --outdir dist/ + - script: python -m build --wheel --outdir dist/ displayName: 'Build wheel' workingDirectory: $(repoRoot)/sdk/python @@ -131,7 +137,7 @@ steps: targetType: inline script: | $wheel = (Get-ChildItem "$(repoRoot)/sdk/python/dist/*.whl" | Select-Object -First 1).FullName - pip install $wheel + pip install --no-deps $wheel # Stage output - task: PowerShell@2 diff --git a/.pipelines/templates/test-python-steps.yml b/.pipelines/templates/test-python-steps.yml index f54a9464..1da74ee2 100644 --- a/.pipelines/templates/test-python-steps.yml +++ b/.pipelines/templates/test-python-steps.yml @@ -8,7 +8,6 @@ parameters: default: false - name: flcWheelsDir type: string - default: '' displayName: 'Path to directory containing the FLC wheels' steps: @@ -99,19 +98,19 @@ steps: Write-Warning "No FLC wheel found matching $filter" } -# Install ORT native packages from the ORT-Nightly feed. -# skip-native-deps strips these from the SDK wheel metadata, so they -# must be installed explicitly for tests to locate the native binaries. -- script: pip install onnxruntime-core onnxruntime-genai-core +- script: pip install onnxruntime-core==1.24.3 onnxruntime-genai-core==0.12.1 displayName: 'Install ORT native packages' +- script: pip install "pydantic>=2.0.0" "requests>=2.32.4" "openai>=2.24.0" + displayName: 'Install pure python dependencies' + - ${{ if not(parameters.isWinML) }}: - - script: python -m build --wheel -C skip-native-deps=true --outdir dist/ + - script: python -m build --wheel --outdir dist/ displayName: 'Build wheel' workingDirectory: $(repoRoot)/sdk/python - ${{ if parameters.isWinML }}: - - script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ + - script: python -m build --wheel -C winml=true --outdir dist/ displayName: 'Build wheel (WinML)' workingDirectory: $(repoRoot)/sdk/python @@ -121,7 +120,7 @@ steps: targetType: inline script: | $wheel = (Get-ChildItem "$(repoRoot)/sdk/python/dist/*.whl" | Select-Object -First 1).FullName - pip install $wheel + pip install --no-deps $wheel - script: pip install coverage pytest>=7.0.0 pytest-timeout>=2.1.0 displayName: 'Install test dependencies' diff --git a/sdk/python/build_backend.py b/sdk/python/build_backend.py index 3789501b..1bdf6cbb 100644 --- a/sdk/python/build_backend.py +++ b/sdk/python/build_backend.py @@ -18,14 +18,13 @@ python -m build --wheel -C winml=true -Skip native deps (use pre-installed foundry-local-core / ORT / GenAI):: - - python -m build --wheel -C skip-native-deps=true - Environment variable fallback (useful in CI pipelines):: FOUNDRY_VARIANT=winml python -m build --wheel - FOUNDRY_SKIP_NATIVE_DEPS=1 python -m build --wheel + +CI usage (install without pulling dependencies):: + + pip install --no-deps """ from __future__ import annotations @@ -51,13 +50,6 @@ _STANDARD_NAME = 'name = "foundry-local-sdk"' _WINML_NAME = 'name = "foundry-local-sdk-winml"' -# Native binary package prefixes to strip when skip-native-deps is active. -_NATIVE_DEP_PREFIXES = ( - "foundry-local-core", - "onnxruntime-core", - "onnxruntime-genai-core", -) - # --------------------------------------------------------------------------- # Variant detection @@ -75,23 +67,6 @@ def _is_winml(config_settings: dict | None) -> bool: return os.environ.get("FOUNDRY_VARIANT", "").lower() == "winml" -def _is_skip_native_deps(config_settings: dict | None) -> bool: - """Return True when native binary dependencies should be omitted. - - When set, ``foundry-local-core``, ``onnxruntime-core``, and - ``onnxruntime-genai-core`` are stripped from requirements.txt so the - wheel is built against whatever versions are already installed. - Useful in CI pipelines that pre-install pipeline-built native wheels. - - Checks ``config_settings["skip-native-deps"]`` first - (set via ``-C skip-native-deps=true``), then falls back to the - ``FOUNDRY_SKIP_NATIVE_DEPS`` environment variable. - """ - if config_settings and str(config_settings.get("skip-native-deps", "")).lower() == "true": - return True - return os.environ.get("FOUNDRY_SKIP_NATIVE_DEPS", "").lower() in ("1", "true") - - # --------------------------------------------------------------------------- # In-place patching context manager # --------------------------------------------------------------------------- @@ -125,48 +100,11 @@ def _patch_for_winml() -> Generator[None, None, None]: _REQUIREMENTS.write_text(requirements_original, encoding="utf-8") -@contextlib.contextmanager -def _strip_native_deps() -> Generator[None, None, None]: - """Temporarily remove native binary deps from requirements.txt. - - Lines starting with any prefix in ``_NATIVE_DEP_PREFIXES`` (case- - insensitive) are removed. The file is restored in the ``finally`` - block. - """ - requirements_original = _REQUIREMENTS.read_text(encoding="utf-8") - try: - filtered = [ - line for line in requirements_original.splitlines(keepends=True) - if not any(line.lstrip().lower().startswith(p) for p in _NATIVE_DEP_PREFIXES) - ] - _REQUIREMENTS.write_text("".join(filtered), encoding="utf-8") - yield - finally: - _REQUIREMENTS.write_text(requirements_original, encoding="utf-8") - - def _apply_patches(config_settings: dict | None): """Return a context manager that applies the appropriate patches.""" - winml = _is_winml(config_settings) - skip_native = _is_skip_native_deps(config_settings) - - @contextlib.contextmanager - def _combined(): - # Stack contexts: WinML swaps requirements first, then strip_native - # removes native deps from whatever requirements are active. - if winml and skip_native: - with _patch_for_winml(), _strip_native_deps(): - yield - elif winml: - with _patch_for_winml(): - yield - elif skip_native: - with _strip_native_deps(): - yield - else: - yield - - return _combined() + if _is_winml(config_settings): + return _patch_for_winml() + return contextlib.nullcontext() # ---------------------------------------------------------------------------