Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pytest
import sys
from pathlib import Path

import pytest
from conda.base.context import context, reset_context
from conda.testing import http_test_server
from conda.testing.fixtures import CondaCLIFixture

pytest_plugins = (
# Add testing fixtures and internal pytest plugins here
Expand All @@ -11,6 +13,30 @@
)
HERE = Path(__file__).parent

# Use the same Python version as the test environment
PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}"


@pytest.fixture(scope="session")
def python_template_env(tmp_path_factory, session_conda_cli: CondaCLIFixture):
"""Create a session-scoped template Python environment for cloning.

This template environment is created once at the start of the test session.
Individual tests can clone it using `conda create --clone` instead of
running a full `conda create` each time, which is faster because it:
- Skips the solver (no SAT solving needed)
- Skips downloading (packages already cached)
- Properly relocates prefixes in metadata and scripts

Yields:
Path to the template environment.
"""
template_path = tmp_path_factory.mktemp("python-template-env")
session_conda_cli(
"create", "--yes", "--prefix", str(template_path), f"python={PYTHON_VERSION}"
)
yield template_path


@pytest.fixture(autouse=True)
def do_not_register_envs(monkeypatch):
Expand Down
99 changes: 32 additions & 67 deletions tests/test_benchmarks.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,13 @@
import sys

import pytest
from pathlib import Path

from conda.testing.fixtures import CondaCLIFixture
from conda.models.match_spec import MatchSpec
import pytest
from conda.common.path import get_python_short_path
from conda.models.match_spec import MatchSpec
from conda.testing.fixtures import CondaCLIFixture

from conda_pypi.build import build_conda
from conda_pypi.convert_tree import ConvertTree
from conda_pypi.downloader import find_and_fetch, get_package_finder
from conda_pypi.build import build_conda

# Use the same Python version as the test environment
PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}"


# @pytest.mark.benchmark
# @pytest.mark.parametrize(
# "packages",
# [
# pytest.param(("imagesize",), id="imagesize"), # small package, few dependencies
# pytest.param(("scipy",), id="scipy"), # slightly larger package
# pytest.param(("jupyterlab",), id="jupyterlab"),
# ],
# )
# def test_conda_pypi_install_basic(
# tmp_path_factory,
# conda_cli: CondaCLIFixture,
# packages: tuple[str],
# benchmark,
# monkeypatch: MonkeyPatch,
# ):
# """Benchmark basic conda pypi install functionality."""

# def setup():
# # Setup function is run every time. So, using benchmarks to run multiple
# # iterations of the test will create new paths for repo_dir and
# # prefix for each iteration. This ensures a clean test without any
# # cached packages and in a clean environment.
# repo_dir = tmp_path_factory.mktemp(f"{'-'.join(packages)}-pkg-repo")
# prefix = str(tmp_path_factory.mktemp(f"{'-'.join(packages)}"))

# monkeypatch.setattr("platformdirs.user_data_dir", lambda s: str(repo_dir))

# conda_cli("create", "--yes", "--prefix", prefix, f"python={PYTHON_VERSION}")
# return (prefix,), {}

# def target(prefix):
# _, _, rc = conda_cli(
# "pypi",
# "--yes",
# "install",
# "--prefix",
# prefix,
# *packages,
# )
# return rc

# result = benchmark.pedantic(
# target,
# setup=setup,
# rounds=2,
# warmup_rounds=0, # no warm up, cleaning the cache every time
# )
# assert result == 0


@pytest.mark.benchmark
Expand All @@ -78,6 +22,7 @@
def test_convert_tree(
tmp_path_factory,
conda_cli: CondaCLIFixture,
python_template_env: Path,
packages: tuple[str],
benchmark,
):
Expand All @@ -86,12 +31,22 @@ def test_convert_tree(

Note: We use small packages to keep benchmark runtime reasonable.
Larger packages like jupyterlab were removed as they took 2+ hours.

Optimization: Uses `conda create --clone` from a session-scoped template
instead of running a full `conda create` each time. This is faster because
it skips the solver and package downloads while still properly handling
prefix relocation.
"""
# Track setup iteration for unique paths
setup_counter = 0

def setup():
repo_dir = tmp_path_factory.mktemp(f"{'-'.join(packages)}-pkg-repo")
prefix = str(tmp_path_factory.mktemp(f"{'-'.join(packages)}"))
conda_cli("create", "--yes", "--prefix", prefix, f"python={PYTHON_VERSION}")
nonlocal setup_counter
setup_counter += 1
repo_dir = tmp_path_factory.mktemp(f"{'-'.join(packages)}-pkg-repo-{setup_counter}")
prefix = str(tmp_path_factory.mktemp(f"{'-'.join(packages)}-{setup_counter}"))

conda_cli("create", "--clone", str(python_template_env), "--prefix", prefix, "--yes")

tree_converter = ConvertTree(prefix, True, repo_dir)
return (tree_converter,), {}
Expand Down Expand Up @@ -119,22 +74,32 @@ def target(tree_converter):
def test_build_conda(
tmp_path_factory,
conda_cli: CondaCLIFixture,
python_template_env: Path,
package: str,
benchmark,
):
"""Benchmark building the conda package from a wheel.

Note: We use small packages to keep benchmark runtime reasonable.
Larger packages like jupyterlab were removed as they took 2+ hours.

Optimization: Uses `conda create --clone` from a session-scoped template
instead of running a full `conda create` each time. This is faster because
it skips the solver and package downloads while still properly handling
prefix relocation.
"""
wheel_dir = tmp_path_factory.mktemp("wheel_dir")
# Track setup iteration for unique paths
setup_counter = 0

def setup():
prefix = str(tmp_path_factory.mktemp(f"{package}"))
build_path = tmp_path_factory.mktemp(f"build-{package}")
output_path = tmp_path_factory.mktemp(f"output-{package}")
nonlocal setup_counter
setup_counter += 1
prefix = str(tmp_path_factory.mktemp(f"{package}-{setup_counter}"))
build_path = tmp_path_factory.mktemp(f"build-{package}-{setup_counter}")
output_path = tmp_path_factory.mktemp(f"output-{package}-{setup_counter}")

conda_cli("create", "--yes", "--prefix", prefix, f"python={PYTHON_VERSION}")
conda_cli("create", "--clone", str(python_template_env), "--prefix", prefix, "--yes")

python_exe = Path(prefix, get_python_short_path())
finder = get_package_finder(prefix)
Expand Down
Loading