Skip to content

feat: Support custom package root #226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ __pycache__
/build
dist
src/tox_uv/version.py

uv.lock
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't really want to publicize setupdir, rather package_root is what we should only advertise.

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]:
Expand Down
4 changes: 2 additions & 2 deletions src/tox_uv/_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Expand Down
4 changes: 2 additions & 2 deletions src/tox_uv/_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
12 changes: 10 additions & 2 deletions src/tox_uv/_run_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be root instead of cwd.

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)
Expand Down
13 changes: 13 additions & 0 deletions src/tox_uv/_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -310,6 +311,18 @@ def _py_info(self) -> PythonInfo: # pragma: win32 no cover
extra={},
)

def package_root(self) -> Path:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a cached property.

try:
return self.core["package_root"]
except KeyError:
config = self.core["tox_root"] / "tox.ini"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be a lot more, than just ini, like toml and various other file sources we support.

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",
Expand Down
54 changes: 54 additions & 0 deletions tests/test_setupdir.py
Original file line number Diff line number Diff line change
@@ -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()