Skip to content
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

Avoid cache collision between wheel and editable wheel builds #3035

Merged
merged 7 commits into from
Jun 17, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 9 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,35 @@ repos:
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.0.272"
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/tox-dev/tox-ini-fmt
rev: "1.3.0"
rev: "1.3.1"
hooks:
- id: tox-ini-fmt
args: ["-p", "fix"]
- repo: https://github.com/tox-dev/pyproject-fmt
rev: "0.11.2"
rev: "0.12.0"
hooks:
- id: pyproject-fmt
additional_dependencies: ["tox>=4.6"]
additional_dependencies: ["tox>=4.6.1"]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v3.0.0-alpha.9-for-vscode"
hooks:
- id: prettier
args: ["--print-width=120", "--prose-wrap=always"]
- repo: https://github.com/asottile/blacken-docs
rev: 1.13.0
rev: 1.14.0
hooks:
- id: blacken-docs
additional_dependencies: [black==23.3]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.0.272"
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
Expand Down
1 change: 1 addition & 0 deletions docs/changelog/3035.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Avoid cache collision between editable wheel build and normal wheel build -- by :user:`f3flight`.
64 changes: 32 additions & 32 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ dependencies = [
"packaging>=23.1",
"platformdirs>=3.5.3",
"pluggy>=1",
"pyproject-api>=1.5.1",
"pyproject-api>=1.5.2",
'tomli>=2.0.1; python_version < "3.11"',
'typing-extensions>=4.6.3; python_version < "3.8"',
"virtualenv>=20.23",
"virtualenv>=20.23.1",
]
optional-dependencies.docs = [
"furo>=2023.5.20",
"sphinx>=7.0.1",
"sphinx-argparse-cli>=1.11",
"sphinx-autodoc-typehints!=1.23.4,>=1.23",
"sphinx-argparse-cli>=1.11.1",
"sphinx-autodoc-typehints!=1.23.4,>=1.23.2",
"sphinx-copybutton>=0.5.2",
"sphinx-inline-tabs>=2023.4.21",
"sphinxcontrib-towncrier>=0.2.1a0",
Expand All @@ -75,7 +75,7 @@ optional-dependencies.testing = [
"build[virtualenv]>=0.10",
"covdefaults>=2.3",
"detect-test-pollution>=1.1.1",
"devpi-process>=0.3",
"devpi-process>=0.3.1",
"diff-cover>=7.6",
"distlib>=0.3.6",
"flaky>=3.7",
Expand All @@ -84,10 +84,10 @@ optional-dependencies.testing = [
"psutil>=5.9.5",
"pytest>=7.3.2",
"pytest-cov>=4.1",
"pytest-mock>=3.10",
"pytest-mock>=3.11.1",
"pytest-xdist>=3.3.1",
"re-assert>=1.1",
'time-machine>=2.9; implementation_name != "pypy"',
'time-machine>=2.10; implementation_name != "pypy"',
"wheel>=0.40",
]
urls.Documentation = "https://tox.wiki"
Expand All @@ -106,6 +106,31 @@ version.source = "vcs"
[tool.black]
line-length = 120

[tool.ruff]
select = ["ALL"]
line-length = 120
target-version = "py37"
isort = {known-first-party = ["tox", "tests"], required-imports = ["from __future__ import annotations"]}
ignore = [
"INP001", # no implicit namespaces here
"D", # ignore documentation for now
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed in `arg`"
"ANN101", # Missing type annotation for `self` in method
"ANN102", # Missing type annotation for `cls` in classmethod"
"D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible
"D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible
"S104", # Possible binding to all interface
]
[tool.ruff.per-file-ignores]
"tests/**/*.py" = [
"S101", # asserts allowed in tests...
"FBT", # don"t care about booleans as positional arguments in tests
"INP001", # no implicit namespace
"D", # don"t care about documentation in tests
"S603", # `subprocess` call: check for execution of untrusted input
"PLR2004", # Magic value used in comparison, consider replacing with a constant variable
]

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--tb=auto -ra --showlocals --no-success-flaky-report"
Expand Down Expand Up @@ -152,28 +177,3 @@ title_format = false
issue_format = ":issue:`{issue}`"
template = "docs/changelog/template.jinja2"
# possible types, all default: feature, bugfix, doc, removal, misc

[tool.ruff]
select = ["ALL"]
line-length = 120
target-version = "py37"
isort = {known-first-party = ["tox", "tests"], required-imports = ["from __future__ import annotations"]}
ignore = [
"INP001", # no implicit namespaces here
"D", # ignore documentation for now
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed in `arg`"
"ANN101", # Missing type annotation for `self` in method
"ANN102", # Missing type annotation for `cls` in classmethod"
"D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible
"D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible
"S104", # Possible binding to all interface
]
[tool.ruff.per-file-ignores]
"tests/**/*.py" = [
"S101", # asserts allowed in tests...
"FBT", # don"t care about booleans as positional arguments in tests
"INP001", # no implicit namespace
"D", # don"t care about documentation in tests
"S603", # `subprocess` call: check for execution of untrusted input
"PLR2004", # Magic value used in comparison, consider replacing with a constant variable
]
14 changes: 7 additions & 7 deletions src/tox/tox_env/python/virtual_env/package/pyproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,13 @@ def __init__(self, root: Path, env: Pep517VirtualEnvPackager) -> None:
self._tox_env = env
self._backend_executor_: LocalSubProcessPep517Executor | None = None
into: dict[str, Any] = {}
pkg_cache = cached(
into,
key=lambda *args, **kwargs: "wheel" if "wheel_directory" in kwargs else "sdist", # noqa: ARG005
)
self.build_wheel = pkg_cache(self.build_wheel) # type: ignore[method-assign]
self.build_sdist = pkg_cache(self.build_sdist) # type: ignore[method-assign]
self.build_editable = pkg_cache(self.build_editable) # type: ignore[method-assign]

for build_type in ("editable", "sdist", "wheel"): # wrap build methods in a cache wrapper

def key(*args: Any, bound_return: str = build_type, **kwargs: Any) -> str: # noqa: ARG001
return bound_return

setattr(self, f"build_{build_type}", cached(into, key=key)(getattr(self, f"build_{build_type}")))

@property
def backend_cmd(self) -> Sequence[str]:
Expand Down
10 changes: 10 additions & 0 deletions tests/demo_pkg_inline/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ def get_requires_for_build_wheel(config_settings: dict[str, str] | None = None)
return [] # pragma: no cover # only executed in non-host pythons


if os.environ.get("BACKEND_HAS_EDITABLE"):

def build_editable(
wheel_directory: str,
config_settings: dict[str, str] | None = None,
metadata_directory: str | None = None,
) -> str:
return build_wheel(wheel_directory, config_settings, metadata_directory)


def build_sdist(sdist_directory: str, config_settings: dict[str, str] | None = None) -> str: # noqa: ARG001
result = f"{name}-{version}.tar.gz" # pragma: win32 cover
with tarfile.open(str(Path(sdist_directory) / result), "w:gz") as tar: # pragma: win32 cover
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,34 @@ def test_project_package_with_deps(tox_project: ToxProjectCreator, demo_pkg_setu
else:
assert found_calls[0] == (".pkg", "install_requires")
assert found_calls[1] == (".pkg", "install_deps")


def test_pyproject_build_editable_and_wheel(tox_project: ToxProjectCreator, demo_pkg_inline: Path) -> None:
# test that build wheel and build editable are cached separately

ini = """
[testenv:.pkg]
set_env= BACKEND_HAS_EDITABLE=1
[testenv:a,b]
package = editable
[testenv:c,d]
package = wheel
"""
proj = tox_project({"tox.ini": ini}, base=demo_pkg_inline)
execute_calls = proj.patch_execute(lambda r: 0 if "install" in r.run_id else None)

result = proj.run("r", "-e", "a,b,c,d", "--notest", "--workdir", str(proj.path / ".tox"))

result.assert_success()
found_calls = [(i[0][0].conf.name, i[0][3].run_id) for i in execute_calls.call_args_list]
assert found_calls == [
(".pkg", "_optional_hooks"),
(".pkg", "get_requires_for_build_wheel"),
(".pkg", "build_editable"),
("a", "install_package"),
("b", "install_package"),
(".pkg", "build_wheel"),
("c", "install_package"),
("d", "install_package"),
(".pkg", "_exit"),
]