Skip to content

Commit 478e047

Browse files
ruiren_microsoftCopilot
andcommitted
Address PR feedback: remove DLL workarounds, keep output queue readable after stop
- Remove _load_dll_win() and SetDllDirectoryW (B1/B2 feedback from baijumeswani) - Remove DLL preload from test/conftest.py (B10) - Keep _output_queue intact after stop() so completed stream stays readable, matching C#/JS SDK behavior (bmehta001 feedback) - Bump foundry-local-core to 1.0.0.dev202604082039 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 08e9c90 commit 478e047

5 files changed

Lines changed: 28 additions & 106 deletions

File tree

sdk/python/requirements-winml.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ pydantic>=2.0.0
22
requests>=2.32.4
33
openai>=2.24.0
44
# WinML native binary packages from the ORT-Nightly PyPI feed.
5-
foundry-local-core-winml==1.0.0rc1
5+
foundry-local-core-winml==1.0.0.dev202604082039
66
onnxruntime-core==1.23.2.3
77
onnxruntime-genai-core==0.13.1

sdk/python/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pydantic>=2.0.0
22
requests>=2.32.4
33
openai>=2.24.0
44
# Standard native binary packages from the ORT-Nightly PyPI feed.
5-
foundry-local-core==1.0.0rc1
5+
foundry-local-core==1.0.0.dev202604082039
66
onnxruntime-core==1.24.4; sys_platform != "linux"
77
onnxruntime-gpu==1.24.4; sys_platform == "linux"
88
onnxruntime-genai-core==0.13.1; sys_platform != "linux"

sdk/python/src/detail/core_interop.py

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -125,32 +125,6 @@ class CoreInterop:
125125
# Returns c_int: 0 = continue, 1 = cancel.
126126
CALLBACK_TYPE = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p)
127127

128-
@staticmethod
129-
def _load_dll_win(dll_path: str):
130-
"""Load a DLL on Windows using ``LOAD_WITH_ALTERED_SEARCH_PATH``.
131-
132-
This flag tells Windows to resolve the DLL's dependencies starting from
133-
the DLL's own directory rather than the process's default search path.
134-
Prevents conflicts with stale same-named DLLs in system directories
135-
(e.g. an old onnxruntime.dll in system32).
136-
137-
The DLL is first loaded via ``LoadLibraryExW`` (which maps it into the
138-
process), then wrapped in a ``ctypes.CDLL`` for Python access.
139-
"""
140-
kernel32 = ctypes.windll.kernel32
141-
kernel32.LoadLibraryExW.restype = ctypes.c_void_p
142-
kernel32.LoadLibraryExW.argtypes = [ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_int]
143-
_LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
144-
145-
handle = kernel32.LoadLibraryExW(dll_path, None, _LOAD_WITH_ALTERED_SEARCH_PATH)
146-
if not handle:
147-
logger.warning("LoadLibraryExW failed for %s (error %d), falling back to ctypes.CDLL",
148-
dll_path, kernel32.GetLastError())
149-
return ctypes.CDLL(dll_path)
150-
151-
# DLL is now mapped; ctypes.CDLL will reuse the loaded module
152-
return ctypes.CDLL(dll_path)
153-
154128
@staticmethod
155129
def _initialize_native_libraries() -> 'NativeBinaryPaths':
156130
"""Load the native Foundry Local Core library and its dependencies.
@@ -185,20 +159,15 @@ def _initialize_native_libraries() -> 'NativeBinaryPaths':
185159
for native_dir in paths.all_dirs():
186160
os.add_dll_directory(str(native_dir))
187161

188-
# Set the DLL search directory so that when ORT/GenAI load their
189-
# own dependencies, they find sibling DLLs from the correct
190-
# directory rather than stale copies in system directories.
191-
ctypes.windll.kernel32.SetDllDirectoryW(str(paths.ort_dir))
192-
193162
# Explicitly pre-load ORT and GenAI so their symbols are globally
194163
# available when Core does P/Invoke lookups at runtime.
195164
# On Windows the PATH manipulation above is sufficient; on
196165
# Linux/macOS we need RTLD_GLOBAL so that dlopen() within the
197166
# Core native code can resolve ORT/GenAI symbols.
198167
# ORT must be loaded before GenAI (GenAI depends on ORT).
199168
if sys.platform.startswith("win"):
200-
CoreInterop._ort_library = CoreInterop._load_dll_win(str(paths.ort))
201-
CoreInterop._genai_library = CoreInterop._load_dll_win(str(paths.genai))
169+
CoreInterop._ort_library = ctypes.CDLL(str(paths.ort))
170+
CoreInterop._genai_library = ctypes.CDLL(str(paths.genai))
202171
else:
203172
CoreInterop._ort_library = ctypes.CDLL(str(paths.ort), mode=os.RTLD_GLOBAL)
204173
CoreInterop._genai_library = ctypes.CDLL(str(paths.genai), mode=os.RTLD_GLOBAL)

sdk/python/src/openai/live_audio_transcription_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,11 @@ def stop(self) -> None:
236236
# 4. Complete the output queue
237237
self._output_queue.put(_SENTINEL)
238238

239-
# 5. Clean up — set _output_queue to None so subsequent calls to
240-
# get_transcription_stream() fail fast instead of hanging.
239+
# 5. Clean up — keep _output_queue intact so that
240+
# get_transcription_stream() returns an empty stream (matching C#/JS
241+
# behavior where the completed stream remains readable).
241242
self._session_handle = None
242243
self._started = False
243-
self._output_queue = None
244244

245245
if response.error is not None:
246246
raise FoundryLocalException(

sdk/python/test/conftest.py

Lines changed: 21 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
import logging
1717
import sys
1818

19-
# ---------------------------------------------------------------------------
20-
# Pre-load ORT/GenAI DLLs from e2e-test-pkgs BEFORE importing the SDK.
21-
#
22-
# The ``_brotli`` C extension (pulled in by httpx → openai → SDK) calls
23-
# ``SetDefaultDllDirectories`` during import, which restricts subsequent
24-
# ``LoadLibraryExW`` calls. Pre-loading here ensures ORT/GenAI are already
25-
# in the process before brotli changes the DLL search behavior.
26-
# ---------------------------------------------------------------------------
19+
import pytest
20+
21+
from pathlib import Path
22+
23+
from foundry_local_sdk.configuration import Configuration, LogLevel
24+
from foundry_local_sdk.foundry_local_manager import FoundryLocalManager
25+
26+
logger = logging.getLogger(__name__)
27+
2728

2829
def _get_e2e_test_pkgs_path():
2930
"""Locate the e2e-test-pkgs directory by walking up from this file."""
@@ -38,40 +39,6 @@ def _get_e2e_test_pkgs_path():
3839
return None
3940
current = parent
4041

41-
if sys.platform.startswith("win"):
42-
import ctypes
43-
44-
def _preload_e2e_dlls():
45-
pkgs = _get_e2e_test_pkgs_path()
46-
if pkgs is None:
47-
return
48-
49-
ort_dll = pkgs / "onnxruntime.dll"
50-
genai_dll = pkgs / "onnxruntime-genai.dll"
51-
if not (ort_dll.exists() and genai_dll.exists()):
52-
return
53-
54-
kernel32 = ctypes.windll.kernel32
55-
kernel32.SetDllDirectoryW(str(pkgs))
56-
os.add_dll_directory(str(pkgs))
57-
os.environ["ORT_LIB_PATH"] = str(ort_dll)
58-
59-
kernel32.LoadLibraryExW.restype = ctypes.c_void_p
60-
kernel32.LoadLibraryExW.argtypes = [ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_int]
61-
kernel32.LoadLibraryExW(str(ort_dll), None, 0x00000008)
62-
kernel32.LoadLibraryExW(str(genai_dll), None, 0x00000008)
63-
64-
_preload_e2e_dlls()
65-
66-
import pytest
67-
68-
from pathlib import Path
69-
70-
from foundry_local_sdk.configuration import Configuration, LogLevel
71-
from foundry_local_sdk.foundry_local_manager import FoundryLocalManager
72-
73-
logger = logging.getLogger(__name__)
74-
7542
TEST_MODEL_ALIAS = "qwen2.5-0.5b"
7643
AUDIO_MODEL_ALIAS = "whisper-tiny"
7744
EMBEDDING_MODEL_ALIAS = "qwen3-0.6b-embedding-generic-cpu"
@@ -206,11 +173,10 @@ def model_load_manager(manager):
206173
# ---------------------------------------------------------------------------
207174

208175
def _preload_and_init_e2e():
209-
"""Pre-load DLLs from e2e-test-pkgs and initialize the SDK for E2E tests.
176+
"""Load DLLs from e2e-test-pkgs and initialize the SDK for E2E tests.
210177
211-
Checks whether ORT is already loaded in the process (from the DLL preload
212-
above) and skips the pre-load if so. Then loads Core.dll, sets up FFI
213-
function signatures, and initializes FoundryLocalManager.
178+
Loads Core.dll, sets up FFI function signatures, and initializes
179+
FoundryLocalManager pointing at the e2e-test-pkgs models directory.
214180
"""
215181
import ctypes
216182
from foundry_local_sdk.detail.core_interop import (
@@ -234,29 +200,16 @@ def _preload_and_init_e2e():
234200
if not (paths.core.exists() and paths.ort.exists() and paths.genai.exists()):
235201
return None, "E2E DLLs not found"
236202

237-
kernel32 = ctypes.windll.kernel32
238-
239-
# Check if ORT is already loaded (e.g. from conftest preload)
240-
kernel32.GetModuleHandleW.restype = ctypes.c_void_p
241-
kernel32.GetModuleHandleW.argtypes = [ctypes.c_wchar_p]
242-
ort_already_loaded = bool(kernel32.GetModuleHandleW("onnxruntime.dll"))
203+
# Register directory so Core.dll can find ORT/GenAI via P/Invoke
204+
os.add_dll_directory(str(pkgs))
205+
os.environ["ORT_LIB_PATH"] = str(paths.ort)
243206

244-
if not ort_already_loaded:
245-
kernel32.SetDllDirectoryW(str(pkgs))
246-
os.add_dll_directory(str(pkgs))
247-
os.environ["ORT_LIB_PATH"] = str(paths.ort)
248-
249-
kernel32.LoadLibraryExW.restype = ctypes.c_void_p
250-
kernel32.LoadLibraryExW.argtypes = [ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_int]
251-
_LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
252-
253-
h_ort = kernel32.LoadLibraryExW(str(paths.ort), None, _LOAD_WITH_ALTERED_SEARCH_PATH)
254-
if not h_ort:
255-
return None, f"Failed to load ORT (WinError {kernel32.GetLastError()})"
256-
257-
h_genai = kernel32.LoadLibraryExW(str(paths.genai), None, _LOAD_WITH_ALTERED_SEARCH_PATH)
258-
if not h_genai:
259-
return None, f"Failed to load GenAI (WinError {kernel32.GetLastError()})"
207+
# Pre-load ORT and GenAI so they are available when Core does P/Invoke
208+
try:
209+
ctypes.CDLL(str(paths.ort))
210+
ctypes.CDLL(str(paths.genai))
211+
except OSError as e:
212+
return None, f"Failed to load ORT/GenAI DLLs: {e}"
260213

261214
# Load Core.dll and set up function signatures
262215
CoreInterop._flcore_library = ctypes.CDLL(str(paths.core))

0 commit comments

Comments
 (0)