mirror of
https://github.com/microsoft/autogen.git
synced 2025-12-14 08:37:54 +00:00
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>
This commit is contained in:
parent
cbd8745f2b
commit
0c9fd64d6e
@ -5,8 +5,10 @@ import asyncio
|
|||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import types
|
||||||
import venv
|
import venv
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import AsyncGenerator, TypeAlias
|
from typing import AsyncGenerator, TypeAlias
|
||||||
@ -21,6 +23,85 @@ from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
|
|||||||
HAS_POWERSHELL: bool = platform.system() == "Windows" and (
|
HAS_POWERSHELL: bool = platform.system() == "Windows" and (
|
||||||
shutil.which("powershell") is not None or shutil.which("pwsh") is not None
|
shutil.which("powershell") is not None or shutil.which("pwsh") is not None
|
||||||
)
|
)
|
||||||
|
IS_MACOS: bool = platform.system() == "Darwin"
|
||||||
|
IS_UV_VENV: bool = (
|
||||||
|
lambda: (
|
||||||
|
(
|
||||||
|
lambda venv_path: (
|
||||||
|
False
|
||||||
|
if not venv_path
|
||||||
|
else (
|
||||||
|
False
|
||||||
|
if not os.path.isfile(os.path.join(venv_path, "pyvenv.cfg"))
|
||||||
|
else (
|
||||||
|
subprocess.run(
|
||||||
|
["grep", "-q", "^uv = ", os.path.join(venv_path, "pyvenv.cfg")],
|
||||||
|
check=False,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
).returncode
|
||||||
|
== 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)(os.environ.get("VIRTUAL_ENV"))
|
||||||
|
)
|
||||||
|
)()
|
||||||
|
HAS_UV: bool = shutil.which("uv") is not None
|
||||||
|
|
||||||
|
|
||||||
|
def create_venv_with_uv(env_dir: str) -> types.SimpleNamespace:
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
["uv", "venv", env_dir],
|
||||||
|
check=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
error_message = f"uv virtual env creation failed with error code {e.returncode}:\n"
|
||||||
|
error_message += f" cmd:\n{e.stdout.decode()}\n"
|
||||||
|
error_message += f" stderr:\n{e.stderr}\n"
|
||||||
|
error_message += f" stdout:\n{e.stdout}"
|
||||||
|
raise RuntimeError(error_message) from e
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"Failed to create uv virtual env: {e}") from e
|
||||||
|
|
||||||
|
# create a venv.EnvBuilder context
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
bin_name = "Scripts"
|
||||||
|
exe_suffix = ".exe"
|
||||||
|
else:
|
||||||
|
bin_name = "bin"
|
||||||
|
exe_suffix = ""
|
||||||
|
|
||||||
|
bin_path = os.path.join(env_dir, bin_name)
|
||||||
|
python_executable = os.path.join(bin_path, f"python{exe_suffix}")
|
||||||
|
py_version_short = f"{sys.version_info.major}.{sys.version_info.minor}"
|
||||||
|
lib_path = os.path.join(env_dir, "lib", f"python{py_version_short}", "site-packages")
|
||||||
|
if not os.path.exists(lib_path):
|
||||||
|
lib_path_fallback = os.path.join(env_dir, "lib")
|
||||||
|
if os.path.exists(lib_path_fallback):
|
||||||
|
lib_path = lib_path_fallback
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Failed to find site-packages in {lib_path} or {lib_path_fallback}")
|
||||||
|
|
||||||
|
context = types.SimpleNamespace(
|
||||||
|
env_dir=env_dir,
|
||||||
|
env_name=os.path.basename(env_dir),
|
||||||
|
prompt=f"({os.path.basename(env_dir)}) ",
|
||||||
|
executable=python_executable,
|
||||||
|
python_dir=os.path.dirname(python_executable),
|
||||||
|
python_exe=os.path.basename(python_executable),
|
||||||
|
inc_path=os.path.join(env_dir, "include"),
|
||||||
|
lib_path=lib_path, # site-packages
|
||||||
|
bin_path=bin_path, # bin or Scripts
|
||||||
|
bin_name=bin_name, # bin or Scripts
|
||||||
|
env_exe=python_executable,
|
||||||
|
env_exec_cmd=python_executable,
|
||||||
|
)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
@pytest_asyncio.fixture(scope="function") # type: ignore
|
@pytest_asyncio.fixture(scope="function") # type: ignore
|
||||||
@ -169,6 +250,10 @@ print("hello world")
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
IS_MACOS and IS_UV_VENV,
|
||||||
|
reason="uv-venv is not supported on macOS.",
|
||||||
|
)
|
||||||
async def test_local_executor_with_custom_venv() -> None:
|
async def test_local_executor_with_custom_venv() -> None:
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
env_builder = venv.EnvBuilder(with_pip=True)
|
env_builder = venv.EnvBuilder(with_pip=True)
|
||||||
@ -190,6 +275,10 @@ async def test_local_executor_with_custom_venv() -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
IS_MACOS and IS_UV_VENV,
|
||||||
|
reason="uv-venv is not supported on macOS.",
|
||||||
|
)
|
||||||
async def test_local_executor_with_custom_venv_in_local_relative_path() -> None:
|
async def test_local_executor_with_custom_venv_in_local_relative_path() -> None:
|
||||||
relative_folder_path = "tmp_dir"
|
relative_folder_path = "tmp_dir"
|
||||||
try:
|
try:
|
||||||
@ -220,6 +309,62 @@ async def test_local_executor_with_custom_venv_in_local_relative_path() -> None:
|
|||||||
shutil.rmtree(relative_folder_path)
|
shutil.rmtree(relative_folder_path)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not HAS_UV,
|
||||||
|
reason="uv is not installed.",
|
||||||
|
)
|
||||||
|
async def test_local_executor_with_custom_uv_venv() -> None:
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
env_builder_context = create_venv_with_uv(temp_dir)
|
||||||
|
|
||||||
|
executor = LocalCommandLineCodeExecutor(work_dir=temp_dir, virtual_env_context=env_builder_context)
|
||||||
|
await executor.start()
|
||||||
|
|
||||||
|
code_blocks = [
|
||||||
|
# https://stackoverflow.com/questions/1871549/how-to-determine-if-python-is-running-inside-a-virtualenv
|
||||||
|
CodeBlock(code="import sys; print(sys.prefix != sys.base_prefix)", language="python"),
|
||||||
|
]
|
||||||
|
cancellation_token = CancellationToken()
|
||||||
|
result = await executor.execute_code_blocks(code_blocks, cancellation_token=cancellation_token)
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert result.output.strip() == "True"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not HAS_UV,
|
||||||
|
reason="uv is not installed.",
|
||||||
|
)
|
||||||
|
async def test_local_executor_with_custom_uv_venv_in_local_relative_path() -> None:
|
||||||
|
relative_folder_path = "tmp_dir"
|
||||||
|
try:
|
||||||
|
if not os.path.isdir(relative_folder_path):
|
||||||
|
os.mkdir(relative_folder_path)
|
||||||
|
|
||||||
|
env_path = os.path.join(relative_folder_path, ".venv")
|
||||||
|
env_builder_context = create_venv_with_uv(env_path)
|
||||||
|
|
||||||
|
executor = LocalCommandLineCodeExecutor(work_dir=relative_folder_path, virtual_env_context=env_builder_context)
|
||||||
|
await executor.start()
|
||||||
|
|
||||||
|
code_blocks = [
|
||||||
|
CodeBlock(code="import sys; print(sys.executable)", language="python"),
|
||||||
|
]
|
||||||
|
cancellation_token = CancellationToken()
|
||||||
|
result = await executor.execute_code_blocks(code_blocks, cancellation_token=cancellation_token)
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
# Check if the expected venv has been used
|
||||||
|
bin_path = os.path.abspath(env_builder_context.bin_path)
|
||||||
|
assert Path(result.output.strip()).parent.samefile(bin_path)
|
||||||
|
finally:
|
||||||
|
if os.path.isdir(relative_folder_path):
|
||||||
|
shutil.rmtree(relative_folder_path)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_serialize_deserialize() -> None:
|
async def test_serialize_deserialize() -> None:
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user