Skip to content

Commit e7deb86

Browse files
prathikrPrathik Rao
andauthored
install python sdk with --no-deps in CI (#582)
allows CI to install custom foundry-local-core from pipeline while built package installs foundry-local-core defined in requirements.txt/requirements-winml.txt --------- Co-authored-by: Prathik Rao <prathikrao@microsoft.com>
1 parent b651d29 commit e7deb86

File tree

3 files changed

+26
-83
lines changed

3 files changed

+26
-83
lines changed

.pipelines/templates/build-python-steps.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ parameters:
1212
default: false
1313
- name: flcWheelsDir
1414
type: string
15-
default: ''
1615
displayName: 'Path to directory containing the FLC wheels (for overriding foundry-local-core)'
1716
- name: outputDir
1817
type: string
@@ -111,16 +110,23 @@ steps:
111110
Write-Warning "No FLC wheel found matching $filter in ${{ parameters.flcWheelsDir }}"
112111
}
113112
113+
- script: pip install onnxruntime-core==1.24.3 onnxruntime-genai-core==0.12.1
114+
displayName: 'Install ORT native packages'
115+
116+
- script: pip install "pydantic>=2.0.0" "requests>=2.32.4" "openai>=2.24.0"
117+
displayName: 'Install pure python dependencies'
118+
114119
# Build wheel — standard or WinML variant
115-
# skip-native-deps=true omits foundry-local-core/onnxruntime pinned versions
116-
# from the wheel metadata, since the pipeline pre-installs its own builds.
120+
# The wheel retains all dependencies in its metadata so end users get
121+
# native packages installed automatically. CI uses --no-deps to avoid
122+
# re-downloading packages that were pre-installed from pipeline builds.
117123
- ${{ if eq(parameters.isWinML, true) }}:
118-
- script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/
124+
- script: python -m build --wheel -C winml=true --outdir dist/
119125
displayName: 'Build wheel (WinML)'
120126
workingDirectory: $(repoRoot)/sdk/python
121127

122128
- ${{ else }}:
123-
- script: python -m build --wheel -C skip-native-deps=true --outdir dist/
129+
- script: python -m build --wheel --outdir dist/
124130
displayName: 'Build wheel'
125131
workingDirectory: $(repoRoot)/sdk/python
126132

@@ -131,7 +137,7 @@ steps:
131137
targetType: inline
132138
script: |
133139
$wheel = (Get-ChildItem "$(repoRoot)/sdk/python/dist/*.whl" | Select-Object -First 1).FullName
134-
pip install $wheel
140+
pip install --no-deps $wheel
135141
136142
# Stage output
137143
- task: PowerShell@2

.pipelines/templates/test-python-steps.yml

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ parameters:
88
default: false
99
- name: flcWheelsDir
1010
type: string
11-
default: ''
1211
displayName: 'Path to directory containing the FLC wheels'
1312

1413
steps:
@@ -99,19 +98,19 @@ steps:
9998
Write-Warning "No FLC wheel found matching $filter"
10099
}
101100
102-
# Install ORT native packages from the ORT-Nightly feed.
103-
# skip-native-deps strips these from the SDK wheel metadata, so they
104-
# must be installed explicitly for tests to locate the native binaries.
105-
- script: pip install onnxruntime-core onnxruntime-genai-core
101+
- script: pip install onnxruntime-core==1.24.3 onnxruntime-genai-core==0.12.1
106102
displayName: 'Install ORT native packages'
107103

104+
- script: pip install "pydantic>=2.0.0" "requests>=2.32.4" "openai>=2.24.0"
105+
displayName: 'Install pure python dependencies'
106+
108107
- ${{ if not(parameters.isWinML) }}:
109-
- script: python -m build --wheel -C skip-native-deps=true --outdir dist/
108+
- script: python -m build --wheel --outdir dist/
110109
displayName: 'Build wheel'
111110
workingDirectory: $(repoRoot)/sdk/python
112111

113112
- ${{ if parameters.isWinML }}:
114-
- script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/
113+
- script: python -m build --wheel -C winml=true --outdir dist/
115114
displayName: 'Build wheel (WinML)'
116115
workingDirectory: $(repoRoot)/sdk/python
117116

@@ -121,7 +120,7 @@ steps:
121120
targetType: inline
122121
script: |
123122
$wheel = (Get-ChildItem "$(repoRoot)/sdk/python/dist/*.whl" | Select-Object -First 1).FullName
124-
pip install $wheel
123+
pip install --no-deps $wheel
125124
126125
- script: pip install coverage pytest>=7.0.0 pytest-timeout>=2.1.0
127126
displayName: 'Install test dependencies'

sdk/python/build_backend.py

Lines changed: 7 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@
1818
1919
python -m build --wheel -C winml=true
2020
21-
Skip native deps (use pre-installed foundry-local-core / ORT / GenAI)::
22-
23-
python -m build --wheel -C skip-native-deps=true
24-
2521
Environment variable fallback (useful in CI pipelines)::
2622
2723
FOUNDRY_VARIANT=winml python -m build --wheel
28-
FOUNDRY_SKIP_NATIVE_DEPS=1 python -m build --wheel
24+
25+
CI usage (install without pulling dependencies)::
26+
27+
pip install --no-deps <wheel>
2928
"""
3029

3130
from __future__ import annotations
@@ -51,13 +50,6 @@
5150
_STANDARD_NAME = 'name = "foundry-local-sdk"'
5251
_WINML_NAME = 'name = "foundry-local-sdk-winml"'
5352

54-
# Native binary package prefixes to strip when skip-native-deps is active.
55-
_NATIVE_DEP_PREFIXES = (
56-
"foundry-local-core",
57-
"onnxruntime-core",
58-
"onnxruntime-genai-core",
59-
)
60-
6153

6254
# ---------------------------------------------------------------------------
6355
# Variant detection
@@ -75,23 +67,6 @@ def _is_winml(config_settings: dict | None) -> bool:
7567
return os.environ.get("FOUNDRY_VARIANT", "").lower() == "winml"
7668

7769

78-
def _is_skip_native_deps(config_settings: dict | None) -> bool:
79-
"""Return True when native binary dependencies should be omitted.
80-
81-
When set, ``foundry-local-core``, ``onnxruntime-core``, and
82-
``onnxruntime-genai-core`` are stripped from requirements.txt so the
83-
wheel is built against whatever versions are already installed.
84-
Useful in CI pipelines that pre-install pipeline-built native wheels.
85-
86-
Checks ``config_settings["skip-native-deps"]`` first
87-
(set via ``-C skip-native-deps=true``), then falls back to the
88-
``FOUNDRY_SKIP_NATIVE_DEPS`` environment variable.
89-
"""
90-
if config_settings and str(config_settings.get("skip-native-deps", "")).lower() == "true":
91-
return True
92-
return os.environ.get("FOUNDRY_SKIP_NATIVE_DEPS", "").lower() in ("1", "true")
93-
94-
9570
# ---------------------------------------------------------------------------
9671
# In-place patching context manager
9772
# ---------------------------------------------------------------------------
@@ -125,48 +100,11 @@ def _patch_for_winml() -> Generator[None, None, None]:
125100
_REQUIREMENTS.write_text(requirements_original, encoding="utf-8")
126101

127102

128-
@contextlib.contextmanager
129-
def _strip_native_deps() -> Generator[None, None, None]:
130-
"""Temporarily remove native binary deps from requirements.txt.
131-
132-
Lines starting with any prefix in ``_NATIVE_DEP_PREFIXES`` (case-
133-
insensitive) are removed. The file is restored in the ``finally``
134-
block.
135-
"""
136-
requirements_original = _REQUIREMENTS.read_text(encoding="utf-8")
137-
try:
138-
filtered = [
139-
line for line in requirements_original.splitlines(keepends=True)
140-
if not any(line.lstrip().lower().startswith(p) for p in _NATIVE_DEP_PREFIXES)
141-
]
142-
_REQUIREMENTS.write_text("".join(filtered), encoding="utf-8")
143-
yield
144-
finally:
145-
_REQUIREMENTS.write_text(requirements_original, encoding="utf-8")
146-
147-
148103
def _apply_patches(config_settings: dict | None):
149104
"""Return a context manager that applies the appropriate patches."""
150-
winml = _is_winml(config_settings)
151-
skip_native = _is_skip_native_deps(config_settings)
152-
153-
@contextlib.contextmanager
154-
def _combined():
155-
# Stack contexts: WinML swaps requirements first, then strip_native
156-
# removes native deps from whatever requirements are active.
157-
if winml and skip_native:
158-
with _patch_for_winml(), _strip_native_deps():
159-
yield
160-
elif winml:
161-
with _patch_for_winml():
162-
yield
163-
elif skip_native:
164-
with _strip_native_deps():
165-
yield
166-
else:
167-
yield
168-
169-
return _combined()
105+
if _is_winml(config_settings):
106+
return _patch_for_winml()
107+
return contextlib.nullcontext()
170108

171109

172110
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)