pyproject-api 1.11.2__tar.gz → 1.11.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.github/workflows/check.yaml +2 -2
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.github/workflows/release.yaml +5 -5
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.pre-commit-config.yaml +5 -5
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/PKG-INFO +3 -3
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/pyproject.toml +13 -13
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/_frontend.py +25 -13
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/_version.py +2 -2
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/_via_fresh_subprocess.py +3 -2
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/test_frontend.py +93 -20
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/test_frontend_setuptools.py +2 -2
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tox.toml +1 -1
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.github/FUNDING.yaml +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.github/SECURITY.md +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.github/dependabot.yaml +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.github/release.yaml +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.gitignore +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/.readthedocs.yml +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/CODE_OF_CONDUCT.md +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/LICENSE +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/README.md +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/docs/api.rst +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/docs/conf.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/docs/index.rst +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/__init__.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/__main__.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/_backend.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/_backend.pyi +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/_util.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/src/pyproject_api/py.typed +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/_build_sdist.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/demo_pkg_inline/build.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/demo_pkg_inline/pyproject.toml +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/test_backend.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/test_main.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/test_util.py +0 -0
- {pyproject_api-1.11.2 → pyproject_api-1.11.4}/tests/test_version.py +0 -0
|
@@ -34,7 +34,7 @@ jobs:
|
|
|
34
34
|
- dev
|
|
35
35
|
- pkg_meta
|
|
36
36
|
os:
|
|
37
|
-
- ubuntu-
|
|
37
|
+
- ubuntu-26.04
|
|
38
38
|
- windows-latest
|
|
39
39
|
- macos-latest
|
|
40
40
|
exclude:
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
fetch-depth: 0
|
|
48
48
|
persist-credentials: false
|
|
49
49
|
- name: Install the latest version of uv
|
|
50
|
-
uses: astral-sh/setup-uv@
|
|
50
|
+
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
51
51
|
with:
|
|
52
52
|
enable-cache: false
|
|
53
53
|
cache-dependency-glob: "pyproject.toml"
|
|
@@ -11,14 +11,14 @@ env:
|
|
|
11
11
|
|
|
12
12
|
jobs:
|
|
13
13
|
build:
|
|
14
|
-
runs-on: ubuntu-
|
|
14
|
+
runs-on: ubuntu-26.04
|
|
15
15
|
steps:
|
|
16
16
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
17
17
|
with:
|
|
18
18
|
fetch-depth: 0
|
|
19
19
|
persist-credentials: false
|
|
20
20
|
- name: Install the latest version of uv
|
|
21
|
-
uses: astral-sh/setup-uv@
|
|
21
|
+
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
22
22
|
with:
|
|
23
23
|
enable-cache: false
|
|
24
24
|
cache-dependency-glob: "pyproject.toml"
|
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
- name: Build package
|
|
27
27
|
run: uv build --python 3.14 --python-preference only-managed --sdist --wheel . --out-dir dist
|
|
28
28
|
- name: Store the distribution packages
|
|
29
|
-
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
29
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
30
30
|
with:
|
|
31
31
|
name: ${{ env.dists-artifact-name }}
|
|
32
32
|
path: dist/*
|
|
@@ -34,7 +34,7 @@ jobs:
|
|
|
34
34
|
release:
|
|
35
35
|
needs:
|
|
36
36
|
- build
|
|
37
|
-
runs-on: ubuntu-
|
|
37
|
+
runs-on: ubuntu-26.04
|
|
38
38
|
environment:
|
|
39
39
|
name: release
|
|
40
40
|
url: https://pypi.org/project/pyproject-api/${{ github.ref_name }}
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
id-token: write
|
|
43
43
|
steps:
|
|
44
44
|
- name: Download all the dists
|
|
45
|
-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
45
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
46
46
|
with:
|
|
47
47
|
name: ${{ env.dists-artifact-name }}
|
|
48
48
|
path: dist/
|
|
@@ -5,7 +5,7 @@ repos:
|
|
|
5
5
|
- id: end-of-file-fixer
|
|
6
6
|
- id: trailing-whitespace
|
|
7
7
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
|
8
|
-
rev: 0.38.
|
|
8
|
+
rev: 0.38.2
|
|
9
9
|
hooks:
|
|
10
10
|
- id: check-github-workflows
|
|
11
11
|
args: [ "--verbose" ]
|
|
@@ -13,17 +13,17 @@ repos:
|
|
|
13
13
|
rev: v2.4.3
|
|
14
14
|
hooks:
|
|
15
15
|
- id: codespell
|
|
16
|
-
additional_dependencies: ["tomli>=2.
|
|
16
|
+
additional_dependencies: ["tomli>=2.4.1"]
|
|
17
17
|
- repo: https://github.com/tox-dev/tox-toml-fmt
|
|
18
|
-
rev: "v1.
|
|
18
|
+
rev: "v1.11.0"
|
|
19
19
|
hooks:
|
|
20
20
|
- id: tox-toml-fmt
|
|
21
21
|
- repo: https://github.com/tox-dev/pyproject-fmt
|
|
22
|
-
rev: "v2.
|
|
22
|
+
rev: "v2.30.1"
|
|
23
23
|
hooks:
|
|
24
24
|
- id: pyproject-fmt
|
|
25
25
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
26
|
-
rev: "v0.16.
|
|
26
|
+
rev: "v0.16.10"
|
|
27
27
|
hooks:
|
|
28
28
|
- id: ruff-format
|
|
29
29
|
- id: ruff
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pyproject-api
|
|
3
|
-
Version: 1.11.
|
|
3
|
+
Version: 1.11.4
|
|
4
4
|
Summary: API to interact with the python pyproject.toml based projects
|
|
5
5
|
Project-URL: Changelog, https://github.com/tox-dev/pyproject-api/releases
|
|
6
6
|
Project-URL: Homepage, https://pyproject-api.readthedocs.io
|
|
@@ -29,8 +29,8 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
29
29
|
Classifier: Topic :: Software Development :: Testing
|
|
30
30
|
Classifier: Topic :: Utilities
|
|
31
31
|
Requires-Python: >=3.10
|
|
32
|
-
Requires-Dist: packaging>=
|
|
33
|
-
Requires-Dist: tomli>=2.
|
|
32
|
+
Requires-Dist: packaging>=26.3
|
|
33
|
+
Requires-Dist: tomli>=2.4.1; python_version < '3.11'
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
|
|
36
36
|
# [`pyproject-api`][RTD]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
build-backend = "hatchling.build"
|
|
3
3
|
requires = [
|
|
4
4
|
"hatch-vcs>=0.5",
|
|
5
|
-
"hatchling>=1.
|
|
5
|
+
"hatchling>=1.32.4",
|
|
6
6
|
]
|
|
7
7
|
|
|
8
8
|
[project]
|
|
@@ -47,8 +47,8 @@ dynamic = [
|
|
|
47
47
|
"version",
|
|
48
48
|
]
|
|
49
49
|
dependencies = [
|
|
50
|
-
"packaging>=
|
|
51
|
-
"tomli>=2.
|
|
50
|
+
"packaging>=26.3",
|
|
51
|
+
"tomli>=2.4.1; python_version<'3.11'",
|
|
52
52
|
]
|
|
53
53
|
urls.Changelog = "https://github.com/tox-dev/pyproject-api/releases"
|
|
54
54
|
urls.Homepage = "https://pyproject-api.readthedocs.io"
|
|
@@ -65,28 +65,28 @@ dev = [
|
|
|
65
65
|
]
|
|
66
66
|
test = [
|
|
67
67
|
"covdefaults>=2.3",
|
|
68
|
-
"pytest>=
|
|
69
|
-
"pytest-cov>=7",
|
|
70
|
-
"pytest-mock>=3.
|
|
71
|
-
"setuptools>=
|
|
68
|
+
"pytest>=9.1.1",
|
|
69
|
+
"pytest-cov>=7.1",
|
|
70
|
+
"pytest-mock>=3.16",
|
|
71
|
+
"setuptools>=84",
|
|
72
72
|
]
|
|
73
73
|
type = [
|
|
74
|
-
"ty
|
|
74
|
+
"ty<0.0.25,>=0.0.24",
|
|
75
75
|
{ include-group = "docs" },
|
|
76
76
|
{ include-group = "test" },
|
|
77
77
|
]
|
|
78
78
|
docs = [
|
|
79
|
-
"furo>=2025.
|
|
79
|
+
"furo>=2025.12.19",
|
|
80
80
|
"sphinx-autodoc-typehints>=3.5.1",
|
|
81
|
-
"sphinx-llm>=
|
|
81
|
+
"sphinx-llm>=1.1",
|
|
82
82
|
]
|
|
83
83
|
lint = [
|
|
84
|
-
"pre-commit-uv>=4.
|
|
84
|
+
"pre-commit-uv>=4.3",
|
|
85
85
|
]
|
|
86
86
|
pkg-meta = [
|
|
87
87
|
"check-wheel-contents>=0.6.3",
|
|
88
|
-
"twine>=
|
|
89
|
-
"uv>=0.
|
|
88
|
+
"twine>=7",
|
|
89
|
+
"uv>=0.12.22",
|
|
90
90
|
]
|
|
91
91
|
|
|
92
92
|
[tool.hatch]
|
|
@@ -17,7 +17,7 @@ from packaging.requirements import Requirement
|
|
|
17
17
|
from pyproject_api._util import ensure_empty_dir
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
|
-
from collections.abc import Iterator
|
|
20
|
+
from collections.abc import Generator, Iterator
|
|
21
21
|
|
|
22
22
|
if sys.version_info >= (3, 11): # pragma: no cover (py311+)
|
|
23
23
|
import tomllib
|
|
@@ -55,11 +55,11 @@ class CmdStatus(ABC):
|
|
|
55
55
|
class RequiresBuildSdistResult(NamedTuple):
|
|
56
56
|
"""Information collected while acquiring the source distribution build dependencies."""
|
|
57
57
|
|
|
58
|
-
#:
|
|
58
|
+
#: source distribution build dependencies
|
|
59
59
|
requires: tuple[Requirement, ...]
|
|
60
60
|
#: backend standard output while acquiring the source distribution build dependencies
|
|
61
61
|
out: str
|
|
62
|
-
#: backend standard
|
|
62
|
+
#: backend standard error while acquiring the source distribution build dependencies
|
|
63
63
|
err: str
|
|
64
64
|
|
|
65
65
|
|
|
@@ -75,7 +75,7 @@ class RequiresBuildWheelResult(NamedTuple):
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
class RequiresBuildEditableResult(NamedTuple):
|
|
78
|
-
"""Information collected while acquiring the wheel build dependencies."""
|
|
78
|
+
"""Information collected while acquiring the editable wheel build dependencies."""
|
|
79
79
|
|
|
80
80
|
#: editable wheel build dependencies
|
|
81
81
|
requires: tuple[Requirement, ...]
|
|
@@ -92,7 +92,7 @@ class MetadataForBuildWheelResult(NamedTuple):
|
|
|
92
92
|
metadata: Path
|
|
93
93
|
#: backend standard output while generating the wheel metadata
|
|
94
94
|
out: str
|
|
95
|
-
#: backend standard
|
|
95
|
+
#: backend standard error while generating the wheel metadata
|
|
96
96
|
err: str
|
|
97
97
|
|
|
98
98
|
|
|
@@ -103,7 +103,7 @@ class MetadataForBuildEditableResult(NamedTuple):
|
|
|
103
103
|
metadata: Path
|
|
104
104
|
#: backend standard output while generating the editable wheel metadata
|
|
105
105
|
out: str
|
|
106
|
-
#: backend standard
|
|
106
|
+
#: backend standard error while generating the editable wheel metadata
|
|
107
107
|
err: str
|
|
108
108
|
|
|
109
109
|
|
|
@@ -114,7 +114,7 @@ class SdistResult(NamedTuple):
|
|
|
114
114
|
sdist: Path
|
|
115
115
|
#: backend standard output while building the source distribution
|
|
116
116
|
out: str
|
|
117
|
-
#: backend standard
|
|
117
|
+
#: backend standard error while building the source distribution
|
|
118
118
|
err: str
|
|
119
119
|
|
|
120
120
|
|
|
@@ -211,10 +211,11 @@ class Frontend(ABC):
|
|
|
211
211
|
folder: Path,
|
|
212
212
|
) -> tuple[Path, tuple[Path, ...], str, str | None, tuple[Requirement, ...], bool]:
|
|
213
213
|
"""
|
|
214
|
-
Frontend creation arguments from a python project folder (
|
|
214
|
+
Frontend creation arguments from a python project folder (should have a ``pyproject.toml`` file per PEP-518).
|
|
215
215
|
|
|
216
216
|
:param folder: the python project folder
|
|
217
217
|
:return: the frontend creation args
|
|
218
|
+
:raises ValueError: if ``build-system`` is not a table, or one of its keys has a type PEP-518 rules out
|
|
218
219
|
|
|
219
220
|
E.g., to create a frontend from a python project folder:
|
|
220
221
|
|
|
@@ -226,16 +227,20 @@ class Frontend(ABC):
|
|
|
226
227
|
if py_project_toml.exists():
|
|
227
228
|
with py_project_toml.open("rb") as file_handler:
|
|
228
229
|
py_project = tomllib.load(file_handler)
|
|
229
|
-
build_system
|
|
230
|
+
if not isinstance(build_system := py_project.get("build-system", {}), dict):
|
|
231
|
+
msg = f"build-system must be a table, got {build_system!r}"
|
|
232
|
+
raise ValueError(msg)
|
|
230
233
|
if "backend-path" in build_system:
|
|
231
|
-
backend_paths: tuple[Path, ...] = tuple(folder / p for p in build_system
|
|
234
|
+
backend_paths: tuple[Path, ...] = tuple(folder / p for p in _str_list(build_system, "backend-path"))
|
|
232
235
|
else:
|
|
233
236
|
backend_paths = ()
|
|
234
237
|
if "requires" in build_system:
|
|
235
|
-
requires: tuple[Requirement, ...] = tuple(Requirement(r) for r in build_system
|
|
238
|
+
requires: tuple[Requirement, ...] = tuple(Requirement(r) for r in _str_list(build_system, "requires"))
|
|
236
239
|
else:
|
|
237
240
|
requires = cls.LEGACY_REQUIRES
|
|
238
|
-
build_backend
|
|
241
|
+
if not isinstance(build_backend := build_system.get("build-backend", cls.LEGACY_BUILD_BACKEND), str):
|
|
242
|
+
msg = f"build-system.build-backend must be a string, got {build_backend!r}"
|
|
243
|
+
raise ValueError(msg)
|
|
239
244
|
else:
|
|
240
245
|
backend_paths = ()
|
|
241
246
|
requires = cls.LEGACY_REQUIRES
|
|
@@ -490,7 +495,7 @@ class Frontend(ABC):
|
|
|
490
495
|
return metadata_directory / basename, out, err
|
|
491
496
|
|
|
492
497
|
@contextmanager
|
|
493
|
-
def _wheel_directory(self) ->
|
|
498
|
+
def _wheel_directory(self) -> Generator[Path, None, None]: # ruff:ignore[no-self-use]
|
|
494
499
|
with TemporaryDirectory() as wheel_directory:
|
|
495
500
|
yield Path(wheel_directory)
|
|
496
501
|
|
|
@@ -528,3 +533,10 @@ class Frontend(ABC):
|
|
|
528
533
|
@contextmanager
|
|
529
534
|
def _send_msg(self, cmd: str, result_file: Path, msg: str) -> Iterator[CmdStatus]:
|
|
530
535
|
raise NotImplementedError
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def _str_list(build_system: dict[str, Any], key: str) -> list[str]:
|
|
539
|
+
if not isinstance(value := build_system[key], list) or not all(isinstance(entry, str) for entry in value):
|
|
540
|
+
msg = f"build-system.{key} must be a list of strings, got {value!r}"
|
|
541
|
+
raise ValueError(msg)
|
|
542
|
+
return value
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.11.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 11,
|
|
21
|
+
__version__ = version = '1.11.4'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 11, 4)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Any, cast
|
|
|
10
10
|
from ._frontend import CmdStatus, Frontend
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
|
-
from collections.abc import
|
|
13
|
+
from collections.abc import Generator
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
16
|
from packaging.requirements import Requirement
|
|
@@ -62,7 +62,7 @@ class SubprocessFrontend(Frontend):
|
|
|
62
62
|
self.executable = sys.executable
|
|
63
63
|
|
|
64
64
|
@contextmanager
|
|
65
|
-
def _send_msg(self, cmd: str, result_file: Path, msg: str) ->
|
|
65
|
+
def _send_msg(self, cmd: str, result_file: Path, msg: str) -> Generator[SubprocessCmdStatus, None, None]: # ruff:ignore[unused-method-argument]
|
|
66
66
|
env = os.environ.copy()
|
|
67
67
|
backend = os.pathsep.join(str(i) for i in self._backend_paths).strip()
|
|
68
68
|
if backend:
|
|
@@ -73,6 +73,7 @@ class SubprocessFrontend(Frontend):
|
|
|
73
73
|
stderr=PIPE,
|
|
74
74
|
stdin=PIPE,
|
|
75
75
|
universal_newlines=True,
|
|
76
|
+
errors="backslashreplace",
|
|
76
77
|
cwd=self._root,
|
|
77
78
|
env=env,
|
|
78
79
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
import subprocess # ruff:ignore[suspicious-subprocess-import]
|
|
4
5
|
import sys
|
|
5
6
|
from pathlib import Path
|
|
@@ -41,8 +42,45 @@ def test_missing_backend(local_builder: Callable[[str], Path]) -> None:
|
|
|
41
42
|
assert "ModuleNotFoundError: No module named " in exc.err
|
|
42
43
|
|
|
43
44
|
|
|
44
|
-
@pytest.
|
|
45
|
-
def
|
|
45
|
+
@pytest.fixture
|
|
46
|
+
def isolated_build_wheel() -> Callable[[Path, str, int], tuple[str, str]]:
|
|
47
|
+
script = dedent("""
|
|
48
|
+
import sys
|
|
49
|
+
from pathlib import Path
|
|
50
|
+
from pyproject_api import SubprocessFrontend
|
|
51
|
+
|
|
52
|
+
root = Path(sys.argv[1])
|
|
53
|
+
frontend = SubprocessFrontend(*SubprocessFrontend.create_args_from_folder(root)[:-1])
|
|
54
|
+
result = frontend.build_wheel(root / "dist", config_settings={"payload": "y" * int(sys.argv[3])})
|
|
55
|
+
print(result.wheel.name)
|
|
56
|
+
print(getattr(result, sys.argv[2]), end="")
|
|
57
|
+
""")
|
|
58
|
+
|
|
59
|
+
def _f(root: Path, output: str, payload_size: int) -> tuple[str, str]:
|
|
60
|
+
# Run the frontend in a child process so a hang fails on the timeout instead of stalling pytest.
|
|
61
|
+
result = subprocess.run(
|
|
62
|
+
[sys.executable, "-X", "utf8", "-c", script, str(root), output, str(payload_size)],
|
|
63
|
+
capture_output=True,
|
|
64
|
+
encoding="utf-8",
|
|
65
|
+
timeout=30,
|
|
66
|
+
check=True,
|
|
67
|
+
)
|
|
68
|
+
assert not result.stderr
|
|
69
|
+
wheel, captured = result.stdout.split("\n", 1)
|
|
70
|
+
return wheel, captured
|
|
71
|
+
|
|
72
|
+
return _f
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@pytest.mark.parametrize(
|
|
76
|
+
("stream", "output"), [pytest.param("stdout", "out", id="stdout"), pytest.param("stderr", "err", id="stderr")]
|
|
77
|
+
)
|
|
78
|
+
def test_large_command_with_backend_output(
|
|
79
|
+
stream: str,
|
|
80
|
+
output: str,
|
|
81
|
+
local_builder: Callable[[str], Path],
|
|
82
|
+
isolated_build_wheel: Callable[[Path, str, int], tuple[str, str]],
|
|
83
|
+
) -> None:
|
|
46
84
|
tmp_path = local_builder(f"""
|
|
47
85
|
import sys
|
|
48
86
|
|
|
@@ -53,27 +91,30 @@ def test_large_command_with_backend_output(stream: str, output: str, local_build
|
|
|
53
91
|
assert config_settings == {{"payload": "y" * 1048576}}
|
|
54
92
|
return "demo-1.0-py3-none-any.whl"
|
|
55
93
|
""")
|
|
56
|
-
|
|
57
|
-
|
|
94
|
+
wheel, captured = isolated_build_wheel(tmp_path, output, 1048576)
|
|
95
|
+
assert (wheel, "x" * 1048576 in captured) == ("demo-1.0-py3-none-any.whl", True)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@pytest.mark.parametrize(
|
|
99
|
+
("stream", "output"), [pytest.param("stdout", "out", id="stdout"), pytest.param("stderr", "err", id="stderr")]
|
|
100
|
+
)
|
|
101
|
+
def test_backend_output_with_invalid_bytes(
|
|
102
|
+
stream: str,
|
|
103
|
+
output: str,
|
|
104
|
+
local_builder: Callable[[str], Path],
|
|
105
|
+
isolated_build_wheel: Callable[[Path, str, int], tuple[str, str]],
|
|
106
|
+
) -> None:
|
|
107
|
+
tmp_path = local_builder(f"""
|
|
58
108
|
import sys
|
|
59
|
-
from pathlib import Path
|
|
60
|
-
from pyproject_api import SubprocessFrontend
|
|
61
109
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
110
|
+
sys.{stream}.buffer.write(b"before\\xffafter")
|
|
111
|
+
sys.{stream}.flush()
|
|
112
|
+
|
|
113
|
+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
|
114
|
+
return "demo-1.0-py3-none-any.whl"
|
|
67
115
|
""")
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
capture_output=True,
|
|
71
|
-
text=True,
|
|
72
|
-
timeout=30,
|
|
73
|
-
check=True,
|
|
74
|
-
)
|
|
75
|
-
assert result.stdout.splitlines() == ["demo-1.0-py3-none-any.whl", "True"]
|
|
76
|
-
assert not result.stderr
|
|
116
|
+
wheel, captured = isolated_build_wheel(tmp_path, output, 0)
|
|
117
|
+
assert (wheel, "before\\xffafter" in captured) == ("demo-1.0-py3-none-any.whl", True)
|
|
77
118
|
|
|
78
119
|
|
|
79
120
|
def test_large_command_with_failed_backend(local_builder: Callable[[str], Path]) -> None:
|
|
@@ -128,6 +169,38 @@ def test_backend_build_sdist_demo_pkg_inline(tmp_path: Path, demo_pkg_inline: Pa
|
|
|
128
169
|
assert result.sdist == tmp_path / "demo_pkg_inline-1.0.0.tar.gz"
|
|
129
170
|
|
|
130
171
|
|
|
172
|
+
@pytest.mark.parametrize(
|
|
173
|
+
("toml", "message"),
|
|
174
|
+
[
|
|
175
|
+
pytest.param(
|
|
176
|
+
'[build-system]\nrequires = "setuptools"',
|
|
177
|
+
"build-system.requires must be a list of strings, got 'setuptools'",
|
|
178
|
+
id="requires-string",
|
|
179
|
+
),
|
|
180
|
+
pytest.param(
|
|
181
|
+
'[build-system]\nrequires = [{name = "setuptools"}]',
|
|
182
|
+
"build-system.requires must be a list of strings, got [{'name': 'setuptools'}]",
|
|
183
|
+
id="requires-table-entry",
|
|
184
|
+
),
|
|
185
|
+
pytest.param(
|
|
186
|
+
'[build-system]\nbackend-path = "build"',
|
|
187
|
+
"build-system.backend-path must be a list of strings, got 'build'",
|
|
188
|
+
id="backend-path-string",
|
|
189
|
+
),
|
|
190
|
+
pytest.param(
|
|
191
|
+
"[build-system]\nbuild-backend = 42",
|
|
192
|
+
"build-system.build-backend must be a string, got 42",
|
|
193
|
+
id="build-backend-int",
|
|
194
|
+
),
|
|
195
|
+
pytest.param('build-system = "setuptools"', "build-system must be a table, got 'setuptools'", id="not-a-table"),
|
|
196
|
+
],
|
|
197
|
+
)
|
|
198
|
+
def test_create_args_from_folder_rejects_bad_build_system_type(tmp_path: Path, toml: str, message: str) -> None:
|
|
199
|
+
(tmp_path / "pyproject.toml").write_text(toml)
|
|
200
|
+
with pytest.raises(ValueError, match=rf"^{re.escape(message)}$"):
|
|
201
|
+
SubprocessFrontend.create_args_from_folder(tmp_path)
|
|
202
|
+
|
|
203
|
+
|
|
131
204
|
def test_backend_obj(tmp_path: Path) -> None:
|
|
132
205
|
toml = """
|
|
133
206
|
[build-system]
|
|
@@ -11,7 +11,7 @@ from pyproject_api._frontend import BackendFailed
|
|
|
11
11
|
from pyproject_api._via_fresh_subprocess import SubprocessFrontend
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
-
from collections.abc import
|
|
14
|
+
from collections.abc import Generator
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
|
|
17
17
|
from _pytest.tmpdir import TempPathFactory
|
|
@@ -149,7 +149,7 @@ class _Result(NamedTuple):
|
|
|
149
149
|
|
|
150
150
|
def test_result_missing(frontend_setuptools: SubprocessFrontend, tmp_path: Path, mocker: MockerFixture) -> None:
|
|
151
151
|
@contextmanager
|
|
152
|
-
def named_temporary_file(prefix: str) ->
|
|
152
|
+
def named_temporary_file(prefix: str) -> Generator[_Result, None, None]:
|
|
153
153
|
write = S_IWUSR | S_IWGRP | S_IWOTH
|
|
154
154
|
base = tmp_path / prefix
|
|
155
155
|
result = base.with_suffix(".json")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|