pyproject-api 1.11.0__tar.gz → 1.11.2__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.0 → pyproject_api-1.11.2}/.github/dependabot.yaml +6 -1
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.github/workflows/check.yaml +2 -2
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.github/workflows/release.yaml +3 -3
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.pre-commit-config.yaml +5 -5
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/PKG-INFO +6 -4
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/README.md +4 -2
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/docs/conf.py +5 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/pyproject.toml +2 -1
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/_util.py +1 -1
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/_version.py +2 -2
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/_via_fresh_subprocess.py +6 -6
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/test_frontend.py +48 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/test_util.py +12 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.github/FUNDING.yaml +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.github/SECURITY.md +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.github/release.yaml +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.gitignore +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/.readthedocs.yml +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/CODE_OF_CONDUCT.md +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/LICENSE +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/docs/api.rst +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/docs/index.rst +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/__init__.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/__main__.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/_backend.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/_backend.pyi +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/_frontend.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/src/pyproject_api/py.typed +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/_build_sdist.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/demo_pkg_inline/build.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/demo_pkg_inline/pyproject.toml +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/test_backend.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/test_frontend_setuptools.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/test_main.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tests/test_version.py +0 -0
- {pyproject_api-1.11.0 → pyproject_api-1.11.2}/tox.toml +0 -0
|
@@ -42,12 +42,12 @@ jobs:
|
|
|
42
42
|
- { os: macos-latest, env: "dev" }
|
|
43
43
|
- { os: macos-latest, env: "pkg_meta" }
|
|
44
44
|
steps:
|
|
45
|
-
- uses: actions/checkout@
|
|
45
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
46
46
|
with:
|
|
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@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
51
51
|
with:
|
|
52
52
|
enable-cache: false
|
|
53
53
|
cache-dependency-glob: "pyproject.toml"
|
|
@@ -13,12 +13,12 @@ jobs:
|
|
|
13
13
|
build:
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
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@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
22
22
|
with:
|
|
23
23
|
enable-cache: false
|
|
24
24
|
cache-dependency-glob: "pyproject.toml"
|
|
@@ -47,6 +47,6 @@ jobs:
|
|
|
47
47
|
name: ${{ env.dists-artifact-name }}
|
|
48
48
|
path: dist/
|
|
49
49
|
- name: Publish to PyPI
|
|
50
|
-
uses: pypa/gh-action-pypi-publish@
|
|
50
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
51
51
|
with:
|
|
52
52
|
attestations: true
|
|
@@ -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.
|
|
8
|
+
rev: 0.38.0
|
|
9
9
|
hooks:
|
|
10
10
|
- id: check-github-workflows
|
|
11
11
|
args: [ "--verbose" ]
|
|
@@ -15,21 +15,21 @@ repos:
|
|
|
15
15
|
- id: codespell
|
|
16
16
|
additional_dependencies: ["tomli>=2.3"]
|
|
17
17
|
- repo: https://github.com/tox-dev/tox-toml-fmt
|
|
18
|
-
rev: "v1.
|
|
18
|
+
rev: "v1.10.3"
|
|
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.29.4"
|
|
23
23
|
hooks:
|
|
24
24
|
- id: pyproject-fmt
|
|
25
25
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
26
|
-
rev: "v0.
|
|
26
|
+
rev: "v0.16.7"
|
|
27
27
|
hooks:
|
|
28
28
|
- id: ruff-format
|
|
29
29
|
- id: ruff
|
|
30
30
|
args: ["--fix", "--unsafe-fixes", "--exit-non-zero-on-fix"]
|
|
31
31
|
- repo: https://github.com/zizmorcore/zizmor-pre-commit
|
|
32
|
-
rev: v1.
|
|
32
|
+
rev: v1.30.1
|
|
33
33
|
hooks:
|
|
34
34
|
- id: zizmor
|
|
35
35
|
- repo: meta
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: pyproject-api
|
|
3
|
-
Version: 1.11.
|
|
3
|
+
Version: 1.11.2
|
|
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
|
|
@@ -33,11 +33,13 @@ Requires-Dist: packaging>=25
|
|
|
33
33
|
Requires-Dist: tomli>=2.3; python_version < '3.11'
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
|
|
36
|
-
# [`pyproject-api`]
|
|
36
|
+
# [`pyproject-api`][RTD]
|
|
37
37
|
|
|
38
38
|
[](https://pypi.org/project/pyproject-api/)
|
|
39
39
|
[](https://pypi.org/project/pyproject-api/)
|
|
41
41
|
[](https://pepy.tech/project/pyproject-api)
|
|
42
42
|
[](https://github.com/tox-dev/pyproject-api/actions/workflows/check.yaml)
|
|
43
|
-
[]
|
|
43
|
+
[][RTD]
|
|
44
|
+
|
|
45
|
+
[RTD]: https://pyproject-api.rtfd.io
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
# [`pyproject-api`]
|
|
1
|
+
# [`pyproject-api`][RTD]
|
|
2
2
|
|
|
3
3
|
[](https://pypi.org/project/pyproject-api/)
|
|
4
4
|
[](https://pypi.org/project/pyproject-api/)
|
|
6
6
|
[](https://pepy.tech/project/pyproject-api)
|
|
7
7
|
[](https://github.com/tox-dev/pyproject-api/actions/workflows/check.yaml)
|
|
8
|
-
[]
|
|
8
|
+
[][RTD]
|
|
9
|
+
|
|
10
|
+
[RTD]: https://pyproject-api.rtfd.io
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# ruff:ignore[undocumented-public-module]
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
import os
|
|
4
5
|
from typing import TYPE_CHECKING
|
|
5
6
|
|
|
6
7
|
from sphinx.domains.python import PythonDomain
|
|
@@ -19,6 +20,7 @@ project_copyright = f"{company}"
|
|
|
19
20
|
version, release = __version__, __version__.split("+")[0]
|
|
20
21
|
|
|
21
22
|
extensions = [
|
|
23
|
+
"sphinx_llm.txt",
|
|
22
24
|
"sphinx.ext.autosectionlabel",
|
|
23
25
|
"sphinx.ext.extlinks",
|
|
24
26
|
"sphinx.ext.autodoc",
|
|
@@ -71,3 +73,6 @@ def setup(app: Sphinx) -> None: # ruff:ignore[undocumented-public-function]
|
|
|
71
73
|
return super().resolve_xref(env, fromdocname, builder, type, target, node, contnode)
|
|
72
74
|
|
|
73
75
|
app.add_domain(PatchedPythonDomain, override=True)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
markdown_http_base = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
|
|
@@ -78,6 +78,7 @@ type = [
|
|
|
78
78
|
docs = [
|
|
79
79
|
"furo>=2025.9.25",
|
|
80
80
|
"sphinx-autodoc-typehints>=3.5.1",
|
|
81
|
+
"sphinx-llm>=0.4.1",
|
|
81
82
|
]
|
|
82
83
|
lint = [
|
|
83
84
|
"pre-commit-uv>=4.2",
|
|
@@ -152,10 +153,10 @@ environment.python-version = "3.14"
|
|
|
152
153
|
|
|
153
154
|
[tool.coverage]
|
|
154
155
|
run.parallel = true
|
|
155
|
-
run.patch = [ "subprocess" ]
|
|
156
156
|
run.plugins = [
|
|
157
157
|
"covdefaults",
|
|
158
158
|
]
|
|
159
|
+
run.patch = [ "subprocess" ]
|
|
159
160
|
paths.source = [
|
|
160
161
|
"src",
|
|
161
162
|
".tox*/*/lib/python*/site-packages",
|
|
@@ -11,7 +11,7 @@ def ensure_empty_dir(path: Path) -> None:
|
|
|
11
11
|
if path.exists():
|
|
12
12
|
if path.is_dir():
|
|
13
13
|
for sub_path in path.iterdir():
|
|
14
|
-
if sub_path.is_dir():
|
|
14
|
+
if sub_path.is_dir() and not sub_path.is_symlink():
|
|
15
15
|
rmtree(sub_path, ignore_errors=True)
|
|
16
16
|
else:
|
|
17
17
|
sub_path.unlink()
|
|
@@ -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.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 11, 2)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -5,7 +5,7 @@ import sys
|
|
|
5
5
|
from contextlib import contextmanager
|
|
6
6
|
from subprocess import PIPE, Popen # ruff:ignore[suspicious-subprocess-import]
|
|
7
7
|
from threading import Thread
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
9
9
|
|
|
10
10
|
from ._frontend import CmdStatus, Frontend
|
|
11
11
|
|
|
@@ -17,14 +17,15 @@ if TYPE_CHECKING:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class SubprocessCmdStatus(CmdStatus, Thread):
|
|
20
|
-
def __init__(self, process: Popen[str]) -> None:
|
|
20
|
+
def __init__(self, process: Popen[str], msg: str | None = None) -> None:
|
|
21
21
|
super().__init__()
|
|
22
22
|
self.process = process
|
|
23
|
+
self._msg = msg
|
|
23
24
|
self._out_err: tuple[str, str] | None = None
|
|
24
25
|
self.start()
|
|
25
26
|
|
|
26
27
|
def run(self) -> None:
|
|
27
|
-
self._out_err = self.process.communicate()
|
|
28
|
+
self._out_err = self.process.communicate(input=self._msg)
|
|
28
29
|
|
|
29
30
|
@property
|
|
30
31
|
def done(self) -> bool:
|
|
@@ -66,7 +67,7 @@ class SubprocessFrontend(Frontend):
|
|
|
66
67
|
backend = os.pathsep.join(str(i) for i in self._backend_paths).strip()
|
|
67
68
|
if backend:
|
|
68
69
|
env["PYTHONPATH"] = backend
|
|
69
|
-
process = Popen(
|
|
70
|
+
process = Popen( # ruff:ignore[subprocess-without-shell-equals-true] # fixed argv, no shell
|
|
70
71
|
args=[self.executable, *self.backend_args],
|
|
71
72
|
stdout=PIPE,
|
|
72
73
|
stderr=PIPE,
|
|
@@ -75,8 +76,7 @@ class SubprocessFrontend(Frontend):
|
|
|
75
76
|
cwd=self._root,
|
|
76
77
|
env=env,
|
|
77
78
|
)
|
|
78
|
-
|
|
79
|
-
yield SubprocessCmdStatus(process)
|
|
79
|
+
yield SubprocessCmdStatus(process, f"{os.linesep}{msg}{os.linesep}")
|
|
80
80
|
|
|
81
81
|
def send_cmd(self, cmd: str, **kwargs: Any) -> tuple[Any, str, str]:
|
|
82
82
|
"""
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import subprocess # ruff:ignore[suspicious-subprocess-import]
|
|
4
|
+
import sys
|
|
3
5
|
from pathlib import Path
|
|
4
6
|
from textwrap import dedent
|
|
5
7
|
from typing import TYPE_CHECKING, Literal
|
|
@@ -39,6 +41,52 @@ def test_missing_backend(local_builder: Callable[[str], Path]) -> None:
|
|
|
39
41
|
assert "ModuleNotFoundError: No module named " in exc.err
|
|
40
42
|
|
|
41
43
|
|
|
44
|
+
@pytest.mark.parametrize(("stream", "output"), [("stdout", "out"), ("stderr", "err")])
|
|
45
|
+
def test_large_command_with_backend_output(stream: str, output: str, local_builder: Callable[[str], Path]) -> None:
|
|
46
|
+
tmp_path = local_builder(f"""
|
|
47
|
+
import sys
|
|
48
|
+
|
|
49
|
+
sys.{stream}.write("x" * 1048576)
|
|
50
|
+
sys.{stream}.flush()
|
|
51
|
+
|
|
52
|
+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
|
53
|
+
assert config_settings == {{"payload": "y" * 1048576}}
|
|
54
|
+
return "demo-1.0-py3-none-any.whl"
|
|
55
|
+
""")
|
|
56
|
+
# Isolate the frontend so a pipe deadlock fails with a timeout instead of hanging pytest.
|
|
57
|
+
script = dedent("""
|
|
58
|
+
import sys
|
|
59
|
+
from pathlib import Path
|
|
60
|
+
from pyproject_api import SubprocessFrontend
|
|
61
|
+
|
|
62
|
+
root = Path(sys.argv[1])
|
|
63
|
+
frontend = SubprocessFrontend(*SubprocessFrontend.create_args_from_folder(root)[:-1])
|
|
64
|
+
result = frontend.build_wheel(root / "dist", config_settings={"payload": "y" * 1048576})
|
|
65
|
+
print(result.wheel.name)
|
|
66
|
+
print("x" * 1048576 in getattr(result, sys.argv[2]))
|
|
67
|
+
""")
|
|
68
|
+
result = subprocess.run(
|
|
69
|
+
[sys.executable, "-c", script, str(tmp_path), output],
|
|
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
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_large_command_with_failed_backend(local_builder: Callable[[str], Path]) -> None:
|
|
80
|
+
tmp_path = local_builder('raise RuntimeError("backend import failed")')
|
|
81
|
+
frontend = SubprocessFrontend(*SubprocessFrontend.create_args_from_folder(tmp_path)[:-1])
|
|
82
|
+
|
|
83
|
+
with pytest.raises(BackendFailed) as context:
|
|
84
|
+
frontend.build_wheel(tmp_path / "dist", config_settings={"payload": "x" * 1048576})
|
|
85
|
+
|
|
86
|
+
assert "failed to start backend" in context.value.err
|
|
87
|
+
assert "RuntimeError: backend import failed" in context.value.err
|
|
88
|
+
|
|
89
|
+
|
|
42
90
|
@pytest.mark.parametrize("cmd", ["build_wheel", "build_sdist"])
|
|
43
91
|
def test_missing_required_cmd(cmd: str, local_builder: Callable[[str], Path]) -> None:
|
|
44
92
|
tmp_path = local_builder("")
|
|
@@ -43,3 +43,15 @@ def test_ensure_empty_dir_on_path_folder(tmp_path: Path) -> None:
|
|
|
43
43
|
(tmp_path / "d").write_text("")
|
|
44
44
|
ensure_empty_dir(tmp_path)
|
|
45
45
|
assert list(tmp_path.iterdir()) == []
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_ensure_empty_dir_on_path_symlink_to_folder(tmp_path: Path) -> None:
|
|
49
|
+
target = tmp_path / "target"
|
|
50
|
+
target.mkdir()
|
|
51
|
+
(target / "c").write_text("")
|
|
52
|
+
path = tmp_path / "a"
|
|
53
|
+
path.mkdir()
|
|
54
|
+
(path / "b").symlink_to(target, target_is_directory=True)
|
|
55
|
+
ensure_empty_dir(path)
|
|
56
|
+
assert list(path.iterdir()) == []
|
|
57
|
+
assert list(target.iterdir()) == [target / "c"]
|
|
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
|