Skip to content

Commit 0c9fd64

Browse files
SongChiYoungekzhu
andauthored
TEST: skip when macos+uv and adding uv venv tests (#6387)
## Why are these changes needed? > The pytest tests test_local_executor_with_custom_venv and test_local_executor_with_custom_venv_in_local_relative_path located in packages/autogen-ext/tests/code_executors/test_commandline_code_executor.py fail when run on macOS (aarch64) using a Python interpreter managed by uv (following the project's recommended development setup). > > The failure occurs during the creation of a nested virtual environment using Python's standard venv.EnvBuilder. Specifically, the attempt to run ensurepip inside the newly created venv fails immediately with a SIGABRT signal. The root cause appears to be a dynamic library loading error (dyld error) where the Python executable inside the newly created venv cannot find its required libpythonX.Y.dylib shared library. So, when MacOS + uv case, skipping that test. And, adding uv-venv case ## Related issue number Closes #6341 ## Checks - [ ] I've included any doc changes needed for <https://microsoft.github.io/autogen/>. See <https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to build and test documentation locally. - [x] I've added tests (if relevant) corresponding to the changes introduced in this PR. - [x] I've made sure all auto checks have passed. Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
1 parent cbd8745 commit 0c9fd64

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

python/packages/autogen-ext/tests/code_executors/test_commandline_code_executor.py

+145
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import os
66
import platform
77
import shutil
8+
import subprocess
89
import sys
910
import tempfile
11+
import types
1012
import venv
1113
from pathlib import Path
1214
from typing import AsyncGenerator, TypeAlias
@@ -21,6 +23,85 @@
2123
HAS_POWERSHELL: bool = platform.system() == "Windows" and (
2224
shutil.which("powershell") is not None or shutil.which("pwsh") is not None
2325
)
26+
IS_MACOS: bool = platform.system() == "Darwin"
27+
IS_UV_VENV: bool = (
28+
lambda: (
29+
(
30+
lambda venv_path: (
31+
False
32+
if not venv_path
33+
else (
34+
False
35+
if not os.path.isfile(os.path.join(venv_path, "pyvenv.cfg"))
36+
else (
37+
subprocess.run(
38+
["grep", "-q", "^uv = ", os.path.join(venv_path, "pyvenv.cfg")],
39+
check=False,
40+
stdout=subprocess.DEVNULL,
41+
stderr=subprocess.DEVNULL,
42+
).returncode
43+
== 0
44+
)
45+
)
46+
)
47+
)(os.environ.get("VIRTUAL_ENV"))
48+
)
49+
)()
50+
HAS_UV: bool = shutil.which("uv") is not None
51+
52+
53+
def create_venv_with_uv(env_dir: str) -> types.SimpleNamespace:
54+
try:
55+
subprocess.run(
56+
["uv", "venv", env_dir],
57+
check=True,
58+
stdout=subprocess.PIPE,
59+
stderr=subprocess.PIPE,
60+
)
61+
except subprocess.CalledProcessError as e:
62+
error_message = f"uv virtual env creation failed with error code {e.returncode}:\n"
63+
error_message += f" cmd:\n{e.stdout.decode()}\n"
64+
error_message += f" stderr:\n{e.stderr}\n"
65+
error_message += f" stdout:\n{e.stdout}"
66+
raise RuntimeError(error_message) from e
67+
except Exception as e:
68+
raise RuntimeError(f"Failed to create uv virtual env: {e}") from e
69+
70+
# create a venv.EnvBuilder context
71+
if platform.system() == "Windows":
72+
bin_name = "Scripts"
73+
exe_suffix = ".exe"
74+
else:
75+
bin_name = "bin"
76+
exe_suffix = ""
77+
78+
bin_path = os.path.join(env_dir, bin_name)
79+
python_executable = os.path.join(bin_path, f"python{exe_suffix}")
80+
py_version_short = f"{sys.version_info.major}.{sys.version_info.minor}"
81+
lib_path = os.path.join(env_dir, "lib", f"python{py_version_short}", "site-packages")
82+
if not os.path.exists(lib_path):
83+
lib_path_fallback = os.path.join(env_dir, "lib")
84+
if os.path.exists(lib_path_fallback):
85+
lib_path = lib_path_fallback
86+
else:
87+
raise RuntimeError(f"Failed to find site-packages in {lib_path} or {lib_path_fallback}")
88+
89+
context = types.SimpleNamespace(
90+
env_dir=env_dir,
91+
env_name=os.path.basename(env_dir),
92+
prompt=f"({os.path.basename(env_dir)}) ",
93+
executable=python_executable,
94+
python_dir=os.path.dirname(python_executable),
95+
python_exe=os.path.basename(python_executable),
96+
inc_path=os.path.join(env_dir, "include"),
97+
lib_path=lib_path, # site-packages
98+
bin_path=bin_path, # bin or Scripts
99+
bin_name=bin_name, # bin or Scripts
100+
env_exe=python_executable,
101+
env_exec_cmd=python_executable,
102+
)
103+
104+
return context
24105

25106

26107
@pytest_asyncio.fixture(scope="function") # type: ignore
@@ -169,6 +250,10 @@ async def test_valid_relative_path(executor_and_temp_dir: ExecutorFixture) -> No
169250

170251

171252
@pytest.mark.asyncio
253+
@pytest.mark.skipif(
254+
IS_MACOS and IS_UV_VENV,
255+
reason="uv-venv is not supported on macOS.",
256+
)
172257
async def test_local_executor_with_custom_venv() -> None:
173258
with tempfile.TemporaryDirectory() as temp_dir:
174259
env_builder = venv.EnvBuilder(with_pip=True)
@@ -190,6 +275,10 @@ async def test_local_executor_with_custom_venv() -> None:
190275

191276

192277
@pytest.mark.asyncio
278+
@pytest.mark.skipif(
279+
IS_MACOS and IS_UV_VENV,
280+
reason="uv-venv is not supported on macOS.",
281+
)
193282
async def test_local_executor_with_custom_venv_in_local_relative_path() -> None:
194283
relative_folder_path = "tmp_dir"
195284
try:
@@ -220,6 +309,62 @@ async def test_local_executor_with_custom_venv_in_local_relative_path() -> None:
220309
shutil.rmtree(relative_folder_path)
221310

222311

312+
@pytest.mark.asyncio
313+
@pytest.mark.skipif(
314+
not HAS_UV,
315+
reason="uv is not installed.",
316+
)
317+
async def test_local_executor_with_custom_uv_venv() -> None:
318+
with tempfile.TemporaryDirectory() as temp_dir:
319+
env_builder_context = create_venv_with_uv(temp_dir)
320+
321+
executor = LocalCommandLineCodeExecutor(work_dir=temp_dir, virtual_env_context=env_builder_context)
322+
await executor.start()
323+
324+
code_blocks = [
325+
# https://stackoverflow.com/questions/1871549/how-to-determine-if-python-is-running-inside-a-virtualenv
326+
CodeBlock(code="import sys; print(sys.prefix != sys.base_prefix)", language="python"),
327+
]
328+
cancellation_token = CancellationToken()
329+
result = await executor.execute_code_blocks(code_blocks, cancellation_token=cancellation_token)
330+
331+
assert result.exit_code == 0
332+
assert result.output.strip() == "True"
333+
334+
335+
@pytest.mark.asyncio
336+
@pytest.mark.skipif(
337+
not HAS_UV,
338+
reason="uv is not installed.",
339+
)
340+
async def test_local_executor_with_custom_uv_venv_in_local_relative_path() -> None:
341+
relative_folder_path = "tmp_dir"
342+
try:
343+
if not os.path.isdir(relative_folder_path):
344+
os.mkdir(relative_folder_path)
345+
346+
env_path = os.path.join(relative_folder_path, ".venv")
347+
env_builder_context = create_venv_with_uv(env_path)
348+
349+
executor = LocalCommandLineCodeExecutor(work_dir=relative_folder_path, virtual_env_context=env_builder_context)
350+
await executor.start()
351+
352+
code_blocks = [
353+
CodeBlock(code="import sys; print(sys.executable)", language="python"),
354+
]
355+
cancellation_token = CancellationToken()
356+
result = await executor.execute_code_blocks(code_blocks, cancellation_token=cancellation_token)
357+
358+
assert result.exit_code == 0
359+
360+
# Check if the expected venv has been used
361+
bin_path = os.path.abspath(env_builder_context.bin_path)
362+
assert Path(result.output.strip()).parent.samefile(bin_path)
363+
finally:
364+
if os.path.isdir(relative_folder_path):
365+
shutil.rmtree(relative_folder_path)
366+
367+
223368
@pytest.mark.asyncio
224369
async def test_serialize_deserialize() -> None:
225370
with tempfile.TemporaryDirectory() as temp_dir:

0 commit comments

Comments
 (0)