diff --git a/.gitignore b/.gitignore index 7e6930d..d6e7223 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ __pycache__ /build dist src/tox_uv/version.py + +uv.lock diff --git a/README.md b/README.md index 4b05014..5c340d9 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,9 @@ overwritten by the VIRTUALENV_SYSTEM_SITE_PACKAGES environment variable. This fl We use `uv pip` to install packages into the virtual environment. The behavior of this can be configured via the following options: +tox-uv resolves your project location based on the `package_root` setting. If that option is not defined, it will fall +back to the `setupdir` value from `tox.ini`, matching how tox itself locates project files. + ### `uv_resolution` This flag, set on a tox environment level, informs `uv` of the desired [resolution strategy]: diff --git a/src/tox_uv/_package.py b/src/tox_uv/_package.py index 6c0b75b..b0166e9 100644 --- a/src/tox_uv/_package.py +++ b/src/tox_uv/_package.py @@ -21,9 +21,9 @@ def id() -> str: def perform_packaging(self, for_env: EnvConfigSet) -> list[Package]: of_type: str = for_env["package"] if of_type == UvPackage.KEY: - return [UvPackage(self.core["tox_root"], for_env["extras"])] + return [UvPackage(self.package_root(), for_env["extras"])] if of_type == UvEditablePackage.KEY: - return [UvEditablePackage(self.core["tox_root"], for_env["extras"])] + return [UvEditablePackage(self.package_root(), for_env["extras"])] return super().perform_packaging(for_env) diff --git a/src/tox_uv/_run.py b/src/tox_uv/_run.py index fe882b3..04f1f5f 100644 --- a/src/tox_uv/_run.py +++ b/src/tox_uv/_run.py @@ -28,8 +28,8 @@ def _external_pkg_tox_env_type(self) -> str: @property def default_pkg_type(self) -> str: - tox_root: Path = self.core["tox_root"] - if not (any((tox_root / i).exists() for i in ("pyproject.toml", "setup.py", "setup.cfg"))): + package_root: Path = self.package_root() + if not (any((package_root / i).exists() for i in ("pyproject.toml", "setup.py", "setup.cfg"))): return "skip" return super().default_pkg_type diff --git a/src/tox_uv/_run_lock.py b/src/tox_uv/_run_lock.py index c399bfd..9a36dfc 100644 --- a/src/tox_uv/_run_lock.py +++ b/src/tox_uv/_run_lock.py @@ -96,7 +96,8 @@ def _setup_env(self) -> None: # noqa: C901 cmd.append("-v") if package == "wheel": # need the package name here but we don't have the packaging infrastructure -> read from pyproject.toml - project_file = self.core["tox_root"] / "pyproject.toml" + root = self.package_root() + project_file = root / "pyproject.toml" name = None if project_file.exists(): with project_file.open("rb") as file_handler: @@ -112,7 +113,14 @@ def _setup_env(self) -> None: # noqa: C901 cmd.extend(("-p", self.env_version_spec())) show = self.options.verbosity > 2 # noqa: PLR2004 - outcome = self.execute(cmd, stdin=StdinSource.OFF, run_id="uv-sync", show=show) + cwd = self.package_root() + outcome = self.execute( + cmd, + stdin=StdinSource.OFF, + run_id="uv-sync", + show=show, + cwd=cwd, + ) outcome.assert_success() if install_pkg is not None: path = Path(install_pkg) diff --git a/src/tox_uv/_venv.py b/src/tox_uv/_venv.py index 92b1a4f..f4767d6 100644 --- a/src/tox_uv/_venv.py +++ b/src/tox_uv/_venv.py @@ -8,6 +8,7 @@ import sys import sysconfig from abc import ABC +from configparser import ConfigParser from functools import cached_property from importlib.resources import as_file, files from pathlib import Path @@ -310,6 +311,18 @@ def _py_info(self) -> PythonInfo: # pragma: win32 no cover extra={}, ) + def package_root(self) -> Path: + try: + return self.core["package_root"] + except KeyError: + config = self.core["tox_root"] / "tox.ini" + if config.is_file(): + parser = ConfigParser() + parser.read(config) + if parser.has_section("tox") and parser.has_option("tox", "setupdir"): + return self.core["tox_root"] / parser.get("tox", "setupdir") + return self.core["tox_root"] + __all__ = [ "UvVenv", diff --git a/tests/test_setupdir.py b/tests/test_setupdir.py new file mode 100644 index 0000000..dbe2317 --- /dev/null +++ b/tests/test_setupdir.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from tox.pytest import ToxProjectCreator + + +def test_setupdir_respected(tox_project: ToxProjectCreator) -> None: + project = tox_project({ + "tox.ini": """ +[tox] +skipsdist = true +setupdir = src +env_list = py +[testenv] +runner = uv-venv-runner +commands = python -c 'print("hello")' +""", + "src": { + "pyproject.toml": """ +[project] +name = 'demo' +version = '0' +""", + }, + }) + result = project.run("-e", "py") + result.assert_success() + + +def test_setupdir_with_package_root(tox_project: ToxProjectCreator) -> None: + project = tox_project({ + "tox.ini": """ +[tox] +skipsdist = true +setupdir = src +env_list = py +[testenv] +runner = uv-venv-runner +package_root = src +commands = python -c 'print("hello")' +""", + "pyproject.toml": "", + "src": { + "pyproject.toml": """ +[project] +name = 'demo' +version = '0' +""", + }, + }) + result = project.run("-e", "py") + result.assert_success()