pyproject-api 1.12.1__tar.gz → 1.12.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.
Files changed (47) hide show
  1. pyproject_api-1.12.2/.github/dependabot.yaml +30 -0
  2. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/workflows/news.yaml +3 -2
  3. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/workflows/prepare-release.yaml +1 -1
  4. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/workflows/release.yaml +7 -7
  5. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/workflows/upgrade-release-tools.yaml +1 -1
  6. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.pre-commit-config.yaml +1 -1
  7. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/PKG-INFO +1 -1
  8. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/docs/changelog.rst +21 -0
  9. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/pylock.toml +45 -48
  10. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/_backend.py +2 -0
  11. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/_backend.pyi +0 -2
  12. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/_frontend.py +4 -0
  13. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/_version.py +2 -2
  14. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/_via_fresh_subprocess.py +8 -3
  15. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/test_backend.py +13 -2
  16. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/test_frontend.py +93 -1
  17. pyproject_api-1.12.1/.github/dependabot.yaml +0 -27
  18. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/FUNDING.yaml +0 -0
  19. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/SECURITY.md +0 -0
  20. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/release.yaml +0 -0
  21. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/workflows/check.yaml +0 -0
  22. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.github/workflows/codeql.yaml +0 -0
  23. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.gitignore +0 -0
  24. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/.readthedocs.yml +0 -0
  25. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/CODE_OF_CONDUCT.md +0 -0
  26. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/CONTRIBUTING.md +0 -0
  27. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/LICENSE +0 -0
  28. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/README.md +0 -0
  29. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/docs/api.rst +0 -0
  30. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/docs/changelog.d/.gitkeep +0 -0
  31. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/docs/changelog.d/template.jinja2 +0 -0
  32. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/docs/conf.py +0 -0
  33. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/docs/contributing.rst +0 -0
  34. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/docs/index.rst +0 -0
  35. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/pyproject.toml +0 -0
  36. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/__init__.py +0 -0
  37. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/__main__.py +0 -0
  38. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/_util.py +0 -0
  39. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/src/pyproject_api/py.typed +0 -0
  40. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/_build_sdist.py +0 -0
  41. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/demo_pkg_inline/build.py +0 -0
  42. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/demo_pkg_inline/pyproject.toml +0 -0
  43. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/test_frontend_setuptools.py +0 -0
  44. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/test_main.py +0 -0
  45. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/test_util.py +0 -0
  46. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tests/test_version.py +0 -0
  47. {pyproject_api-1.12.1 → pyproject_api-1.12.2}/tox.toml +0 -0
@@ -0,0 +1,30 @@
1
+ version: 2
2
+ multi-ecosystem-groups:
3
+ dependencies:
4
+ schedule:
5
+ interval: weekly
6
+ day: tuesday
7
+ labels:
8
+ - dependencies
9
+ - skip news
10
+ updates:
11
+ - package-ecosystem: github-actions
12
+ directory: /
13
+ patterns:
14
+ - '*'
15
+ multi-ecosystem-group: dependencies
16
+ labels:
17
+ - dependencies
18
+ - skip news
19
+ cooldown:
20
+ default-days: 7
21
+ - package-ecosystem: pre-commit
22
+ directory: /
23
+ patterns:
24
+ - '*'
25
+ multi-ecosystem-group: dependencies
26
+ labels:
27
+ - dependencies
28
+ - skip news
29
+ cooldown:
30
+ default-days: 7
@@ -7,6 +7,7 @@ concurrency:
7
7
  cancel-in-progress: true
8
8
  permissions:
9
9
  contents: read
10
+ pull-requests: read
10
11
  jobs:
11
12
  changelog:
12
13
  name: 📝 News fragment
@@ -24,9 +25,9 @@ jobs:
24
25
  python-version: "3.15"
25
26
  enable-cache: false
26
27
  - name: 📦 Install locked release tools
27
- uses: tox-dev/github-workflows/install-locked-tools@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
28
+ uses: tox-dev/github-workflows/install-locked-tools@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
28
29
  with:
29
30
  groups: release-news
30
31
  venv: ${{ runner.temp }}/release-tools
31
32
  - name: 🔍 Validate news fragments
32
- uses: tox-dev/github-workflows/validate-news@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
33
+ uses: tox-dev/github-workflows/validate-news@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
@@ -16,7 +16,7 @@ permissions: {}
16
16
  jobs:
17
17
  prepare:
18
18
  name: 🏷️ Prepare Towncrier release
19
- uses: tox-dev/github-workflows/.github/workflows/prepare-towncrier-release.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
19
+ uses: tox-dev/github-workflows/.github/workflows/prepare-towncrier-release.yaml@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
20
20
  permissions:
21
21
  contents: read
22
22
  pull-requests: read
@@ -10,7 +10,7 @@ concurrency:
10
10
  jobs:
11
11
  build:
12
12
  name: 🏗️ Build
13
- uses: tox-dev/github-workflows/.github/workflows/validate-python-release.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
13
+ uses: tox-dev/github-workflows/.github/workflows/validate-python-release.yaml@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
14
14
  permissions:
15
15
  contents: read
16
16
  github-notes:
@@ -33,17 +33,17 @@ jobs:
33
33
  python-version: "3.15"
34
34
  enable-cache: false
35
35
  - name: 📦 Install locked release tools
36
- uses: tox-dev/github-workflows/install-locked-tools@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
36
+ uses: tox-dev/github-workflows/install-locked-tools@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
37
37
  with:
38
38
  groups: release-notes
39
39
  venv: ${{ runner.temp }}/release-tools
40
40
  - name: 🏷️ Select previous tag
41
41
  id: previous
42
- uses: tox-dev/github-workflows/select-previous-tag@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
42
+ uses: tox-dev/github-workflows/select-previous-tag@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
43
43
  with:
44
44
  tag: ${{ github.ref_name }}
45
45
  - name: 📝 Render release notes
46
- uses: tox-dev/github-workflows/render-release-notes@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
46
+ uses: tox-dev/github-workflows/render-release-notes@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
47
47
  with:
48
48
  tag: ${{ github.ref_name }}
49
49
  previous: ${{ steps.previous.outputs.previous }}
@@ -73,7 +73,7 @@ jobs:
73
73
  artifact-ids: ${{ needs.build.outputs.distributions-artifact-id }}
74
74
  path: dist/
75
75
  - name: 🚀 Publish to PyPI
76
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
76
+ uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
77
77
  with:
78
78
  packages-dir: dist
79
79
  attestations: true
@@ -102,13 +102,13 @@ jobs:
102
102
  artifact-ids: ${{ needs.github-notes.outputs.artifact-id }}
103
103
  path: ${{ runner.temp }}
104
104
  - name: 🔍 Verify PyPI artifacts
105
- uses: tox-dev/github-workflows/reconcile-pypi-artifacts@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
105
+ uses: tox-dev/github-workflows/reconcile-pypi-artifacts@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
106
106
  with:
107
107
  project: pyproject-api
108
108
  version: ${{ github.ref_name }}
109
109
  dist: dist
110
110
  - name: 🚀 Publish GitHub release
111
- uses: tox-dev/github-workflows/publish-github-release@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
111
+ uses: tox-dev/github-workflows/publish-github-release@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
112
112
  with:
113
113
  tag: ${{ github.ref_name }}
114
114
  commit: ${{ github.sha }}
@@ -10,7 +10,7 @@ concurrency:
10
10
  jobs:
11
11
  upgrade:
12
12
  name: 🔀 Upgrade release tools
13
- uses: tox-dev/github-workflows/.github/workflows/upgrade-release-tools.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1
13
+ uses: tox-dev/github-workflows/.github/workflows/upgrade-release-tools.yaml@57a765127aae73adf7d0e24a7fe0f067f2d3ea3e # 6.2.1
14
14
  permissions:
15
15
  contents: read
16
16
  secrets:
@@ -44,7 +44,7 @@ repos:
44
44
  ^docs/changelog[.]rst$ # Only the generated release history.
45
45
  args: ["-l", "120", "--preserve-adornments"]
46
46
  additional_dependencies:
47
- - "sphinx==9.1.0"
47
+ - "sphinx==9.1.1"
48
48
  - repo: https://github.com/zizmorcore/zizmor-pre-commit
49
49
  rev: c92afdf2c6ca336aaa8f39e2bd8d48f62dbd8e1f # frozen: v1.31.1
50
50
  hooks:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyproject-api
3
- Version: 1.12.1
3
+ Version: 1.12.2
4
4
  Import-Name: pyproject_api
5
5
  Summary: API to interact with the python pyproject.toml based projects
6
6
  Project-URL: Changelog, https://github.com/tox-dev/pyproject-api/blob/main/docs/changelog.rst
@@ -5,6 +5,27 @@ Release History
5
5
 
6
6
  .. towncrier release notes start
7
7
 
8
+ .. _release-1-12-2:
9
+
10
+ v1.12.2 (2026-10-28)
11
+ --------------------
12
+
13
+ .. _release-1-12-2-fixed:
14
+
15
+ Fixed
16
+ ^^^^^
17
+
18
+ - Drop the backend proxy stub declarations for its private commands; one named a method the proxy does not have
19
+ (:pr:`331`) by :user:`tridev-tej` and :user:`gaborbernat`.
20
+ - Keep a trailing space in the last backend path when putting it on ``PYTHONPATH`` (:pr:`329`) by :user:`jdotc1` and
21
+ :user:`gaborbernat`.
22
+ - Preserve ``BackendFailed`` details when copying or pickling an exception, including when a build runs in a process
23
+ pool (:pr:`337`) by :user:`jdotc1`.
24
+ - Stop the backend from crashing when it prints a path its standard output encoding cannot represent (:pr:`330`) by
25
+ :user:`nk-batman21` and :user:`gaborbernat`.
26
+ - Stop the backend process and join its output collection thread when a frontend call is interrupted (:pr:`332`) by
27
+ :user:`zfz2005` and :user:`gaborbernat`.
28
+
8
29
  .. _release-1-12-1:
9
30
 
10
31
  v1.12.1 (2026-10-27)
@@ -180,28 +180,28 @@ sha256 = "d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9"
180
180
 
181
181
  [[packages]]
182
182
  name = "certifi"
183
- version = "2026.10.18"
183
+ version = "2026.10.19"
184
184
  marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"type\" in dependency_groups"
185
185
  requires-python = ">=3.7"
186
186
  index = "https://pypi.org/simple/"
187
187
 
188
188
  [packages.sdist]
189
- name = "certifi-2026.10.18.tar.gz"
190
- upload-time = 2026-10-18 16:21:07.655710+00:00
191
- url = "https://files.pythonhosted.org/packages/7e/eb/a2aa1ac3ea30dd3f30ca57f40232138b6b0040719316ecb85daf61167771/certifi-2026.10.18.tar.gz"
192
- size = 135227
189
+ name = "certifi-2026.10.19.tar.gz"
190
+ upload-time = 2026-10-20 02:24:16.604828+00:00
191
+ url = "https://files.pythonhosted.org/packages/a6/bd/1436c50cc46699de0230fbaacc1d1de7bfec413176099949e9d5112e88f2/certifi-2026.10.19.tar.gz"
192
+ size = 137598
193
193
 
194
194
  [packages.sdist.hashes]
195
- sha256 = "b9995d97b64d0431a5af837d8ca8cd6238104d1f319f04bd93ea43124d6c861e"
195
+ sha256 = "035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae"
196
196
 
197
197
  [[packages.wheels]]
198
- name = "certifi-2026.10.18-py3-none-any.whl"
199
- upload-time = 2026-10-18 16:21:06.276884+00:00
200
- url = "https://files.pythonhosted.org/packages/08/ba/95dd616042484f7c83a06974388b37b837732740ee70bc5dc715b5fcd55a/certifi-2026.10.18-py3-none-any.whl"
201
- size = 134093
198
+ name = "certifi-2026.10.19-py3-none-any.whl"
199
+ upload-time = 2026-10-20 02:24:15.072385+00:00
200
+ url = "https://files.pythonhosted.org/packages/c4/51/29046e48f693c54e5b7412216d447a1d8362c9653148d98c02cdf65fa733/certifi-2026.10.19-py3-none-any.whl"
201
+ size = 136464
202
202
 
203
203
  [packages.wheels.hashes]
204
- sha256 = "73191c47aaa79da394e8fee2dbc2ec827432cab56311122c9e47abf79e390f62"
204
+ sha256 = "42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b"
205
205
 
206
206
  [[packages]]
207
207
  name = "cffi"
@@ -1942,28 +1942,28 @@ sha256 = "0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137"
1942
1942
 
1943
1943
  [[packages]]
1944
1944
  name = "setuptools"
1945
- version = "84.0.0"
1945
+ version = "84.2.0"
1946
1946
  marker = "\"build\" in dependency_groups or \"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups"
1947
1947
  requires-python = ">=3.10"
1948
1948
  index = "https://pypi.org/simple/"
1949
1949
 
1950
1950
  [packages.sdist]
1951
- name = "setuptools-84.0.0.tar.gz"
1952
- upload-time = 2026-08-08 18:27:58.365696+00:00
1953
- url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz"
1954
- size = 1168449
1951
+ name = "setuptools-84.2.0.tar.gz"
1952
+ upload-time = 2026-10-19 20:38:03.407523+00:00
1953
+ url = "https://files.pythonhosted.org/packages/63/40/e2c41d00a4bfea5548c31420a74c6cf149cc0e7c36b45c4c82202ce867aa/setuptools-84.2.0.tar.gz"
1954
+ size = 1227656
1955
1955
 
1956
1956
  [packages.sdist.hashes]
1957
- sha256 = "f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73"
1957
+ sha256 = "6f445ca2ce864605f81e223f262b4c94ffcb9a4a63473bae0ed7be5aab0291da"
1958
1958
 
1959
1959
  [[packages.wheels]]
1960
- name = "setuptools-84.0.0-py3-none-any.whl"
1961
- upload-time = 2026-08-08 18:27:56.719708+00:00
1962
- url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"
1963
- size = 818216
1960
+ name = "setuptools-84.2.0-py3-none-any.whl"
1961
+ upload-time = 2026-10-19 20:38:01.629093+00:00
1962
+ url = "https://files.pythonhosted.org/packages/dd/a2/2e1af99d56c8145aa69496026c7e5fd7b6ec759b500c3ad697e2062832dc/setuptools-84.2.0-py3-none-any.whl"
1963
+ size = 875816
1964
1964
 
1965
1965
  [packages.wheels.hashes]
1966
- sha256 = "51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670"
1966
+ sha256 = "8cc107ac7a403105dc8d6477664171f36135fab26adf8b5e0edaebc313f39b21"
1967
1967
 
1968
1968
  [[packages]]
1969
1969
  name = "setuptools-scm"
@@ -2047,7 +2047,7 @@ sha256 = "fa30e3ba4809cb81ce1f3209f2fbe3e779fc445f0439bc147a0d7c4601743f21"
2047
2047
 
2048
2048
  [[packages]]
2049
2049
  name = "sphinx"
2050
- version = "9.1.0"
2050
+ version = "9.1.1"
2051
2051
  marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"type\" in dependency_groups"
2052
2052
  requires-python = ">=3.12"
2053
2053
  dependencies = [
@@ -2071,22 +2071,22 @@ dependencies = [
2071
2071
  index = "https://pypi.org/simple/"
2072
2072
 
2073
2073
  [packages.sdist]
2074
- name = "sphinx-9.1.0.tar.gz"
2075
- upload-time = 2025-12-31 15:09:27.646696+00:00
2076
- url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz"
2077
- size = 8718324
2074
+ name = "sphinx-9.1.1.tar.gz"
2075
+ upload-time = 2026-10-20 00:41:13.960930+00:00
2076
+ url = "https://files.pythonhosted.org/packages/fc/73/567727fc8c8d85bc3adc88a246e12937cfda8d565cf1d80e85bceaa61fe5/sphinx-9.1.1.tar.gz"
2077
+ size = 8725638
2078
2078
 
2079
2079
  [packages.sdist.hashes]
2080
- sha256 = "7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb"
2080
+ sha256 = "48b627f02908f22c601b3ba9c7b17265b4f315dd05c8bc64cd4da41183f44fbc"
2081
2081
 
2082
2082
  [[packages.wheels]]
2083
- name = "sphinx-9.1.0-py3-none-any.whl"
2084
- upload-time = 2025-12-31 15:09:25.561651+00:00
2085
- url = "https://files.pythonhosted.org/packages/73/f7/b1884cb3188ab181fc81fa00c266699dab600f927a964df02ec3d5d1916a/sphinx-9.1.0-py3-none-any.whl"
2086
- size = 3921742
2083
+ name = "sphinx-9.1.1-py3-none-any.whl"
2084
+ upload-time = 2026-10-20 00:41:11.288695+00:00
2085
+ url = "https://files.pythonhosted.org/packages/47/18/3c66ea76da7de47e716b181c35bdbfafbd5e9af0bb247b14578e9de348e9/sphinx-9.1.1-py3-none-any.whl"
2086
+ size = 3923559
2087
2087
 
2088
2088
  [packages.wheels.hashes]
2089
- sha256 = "c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978"
2089
+ sha256 = "f8b60013ce25017be41a509e5c2d265bc1918410061315c36b809c7f335646c0"
2090
2090
 
2091
2091
  [[packages]]
2092
2092
  name = "sphinx-autodoc-typehints"
@@ -2627,28 +2627,28 @@ sha256 = "0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3"
2627
2627
 
2628
2628
  [[packages]]
2629
2629
  name = "uv"
2630
- version = "0.13.1"
2630
+ version = "0.13.3"
2631
2631
  marker = "\"dev\" in dependency_groups or \"lint\" in dependency_groups or \"pkg-meta\" in dependency_groups"
2632
2632
  requires-python = ">=3.8"
2633
2633
  index = "https://pypi.org/simple/"
2634
2634
 
2635
2635
  [packages.sdist]
2636
- name = "uv-0.13.1.tar.gz"
2637
- upload-time = 2026-10-14 05:13:35.353145+00:00
2638
- url = "https://files.pythonhosted.org/packages/ef/10/81f499de381ac81e09961e1c19255c5cf49563ac418464def4190b6c7400/uv-0.13.1.tar.gz"
2639
- size = 7434239
2636
+ name = "uv-0.13.3.tar.gz"
2637
+ upload-time = 2026-10-20 01:13:40.241842+00:00
2638
+ url = "https://files.pythonhosted.org/packages/b2/0d/0cf59876b94f537055fdcc6a32126fd9abb841620b6589ae3fcbf6e21f69/uv-0.13.3.tar.gz"
2639
+ size = 7477898
2640
2640
 
2641
2641
  [packages.sdist.hashes]
2642
- sha256 = "6df50a86b09be66a413f8f1b16258d585d4dd1cbff591077ae1e6f65c26de2eb"
2642
+ sha256 = "fe8587cb414b324753eb2c1b2a54d2f93b2aed7e9cf02e9c1efa3776547a3aae"
2643
2643
 
2644
2644
  [[packages.wheels]]
2645
- name = "uv-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
2646
- upload-time = 2026-10-14 05:13:13.069021+00:00
2647
- url = "https://files.pythonhosted.org/packages/14/0b/6602a613533602e7a083e908c4375f9b0e78a94ba2e21c29b21c41a0a611/uv-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
2648
- size = 17279385
2645
+ name = "uv-0.13.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
2646
+ upload-time = 2026-10-20 01:13:11.825804+00:00
2647
+ url = "https://files.pythonhosted.org/packages/7e/fa/45e1751beda39226d5472e6bb068747115a06f19c2559a8810aac9b881b7/uv-0.13.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
2648
+ size = 17301030
2649
2649
 
2650
2650
  [packages.wheels.hashes]
2651
- sha256 = "696dcf6d807d85da978f4db8472da81dccc1254b18b52cbd1367c4d923c421e0"
2651
+ sha256 = "8d9ba65db55f3701908b09394cb7d3248be28496aab6bd9a96e8e870261ad372"
2652
2652
 
2653
2653
  [[packages]]
2654
2654
  name = "vcs-versioning"
@@ -2771,7 +2771,7 @@ sha256 = "3fa599046443d4ca830d06e3d180cd0a675d5871af0a68daa5623318bb4d17e3"
2771
2771
 
2772
2772
  [tool.nab]
2773
2773
  nab-version = "0.0.22"
2774
- created-at = 2026-10-26 20:06:51.656389+00:00
2774
+ created-at = 2026-10-27 13:49:49.388379+00:00
2775
2775
  command-line = [
2776
2776
  "nab",
2777
2777
  "lock",
@@ -2779,9 +2779,6 @@ command-line = [
2779
2779
  "--all-extras",
2780
2780
  "--no-cache",
2781
2781
  "--upgrade",
2782
- "pyproject.toml",
2783
- "--output",
2784
- "pylock.toml",
2785
2782
  ]
2786
2783
  input-path = "pyproject.toml"
2787
2784
  mode = "universal"
@@ -150,4 +150,6 @@ def read_line(fd=0):
150
150
 
151
151
 
152
152
  if __name__ == "__main__":
153
+ # printed paths may hold characters the stdout encoding cannot represent
154
+ sys.stdout.reconfigure(errors="backslashreplace") # type: ignore[unresolved-attribute] # stub says TextIO
153
155
  sys.exit(run(sys.argv[1:]))
@@ -10,8 +10,6 @@ class BackendProxy:
10
10
 
11
11
  def __init__(self, backend_module: str, backend_obj: str | None) -> None: ...
12
12
  def __call__(self, name: str, *args: Any, **kwargs: Any) -> Any: ...
13
- def _exit(self) -> None: ...
14
- def _optional_commands(self) -> dict[str, bool]: ...
15
13
 
16
14
  def run(argv: Sequence[str]) -> int: ...
17
15
  def read_line(fd: int = 0) -> bytearray: ...
@@ -152,6 +152,10 @@ class BackendFailed(RuntimeError): # ruff:ignore[error-suffix-on-exception-name
152
152
  #: the string representation of the exception thrown
153
153
  self.exc_msg: str = result.get("exc_msg", "missing Exception message")
154
154
 
155
+ def __reduce__(self) -> tuple[type[BackendFailed], tuple[dict[str, Any], str, str], dict[str, Any]]:
156
+ result = {"code": self.code, "exc_type": self.exc_type, "exc_msg": self.exc_msg}
157
+ return self.__class__, (result, self.out, self.err), self.__dict__
158
+
155
159
  def __str__(self) -> str:
156
160
  return (
157
161
  f"packaging backend failed{'' if self.code is None else f' (code={self.code})'}, "
@@ -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.12.1'
22
- __version_tuple__ = version_tuple = (1, 12, 1)
21
+ __version__ = version = '1.12.2'
22
+ __version_tuple__ = version_tuple = (1, 12, 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 TYPE_CHECKING, Any, cast
8
+ from typing import TYPE_CHECKING, Any, Final, cast
9
9
 
10
10
  from ._frontend import CmdStatus, Frontend
11
11
 
@@ -64,7 +64,7 @@ class SubprocessFrontend(Frontend):
64
64
  @contextmanager
65
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
- backend = os.pathsep.join(str(i) for i in self._backend_paths).strip()
67
+ backend = os.pathsep.join(str(i) for i in self._backend_paths)
68
68
  if backend:
69
69
  env["PYTHONPATH"] = backend
70
70
  process = Popen( # ruff:ignore[subprocess-without-shell-equals-true] # fixed argv, no shell
@@ -77,7 +77,12 @@ class SubprocessFrontend(Frontend):
77
77
  cwd=self._root,
78
78
  env=env,
79
79
  )
80
- yield SubprocessCmdStatus(process, f"{os.linesep}{msg}{os.linesep}")
80
+ status: Final = SubprocessCmdStatus(process, f"{os.linesep}{msg}{os.linesep}")
81
+ try:
82
+ yield status
83
+ finally:
84
+ process.kill()
85
+ status.join()
81
86
 
82
87
  def send_cmd(self, cmd: str, **kwargs: Any) -> tuple[Any, str, str]:
83
88
  """
@@ -5,11 +5,11 @@ import os
5
5
  import subprocess # ruff:ignore[suspicious-subprocess-import]
6
6
  import sys
7
7
  from textwrap import dedent
8
- from typing import TYPE_CHECKING, Any
8
+ from typing import TYPE_CHECKING, Any, Final
9
9
 
10
10
  import pytest
11
11
 
12
- from pyproject_api import _backend
12
+ from pyproject_api import SubprocessFrontend, _backend
13
13
  from pyproject_api._backend import BackendProxy, read_line, run
14
14
 
15
15
  if TYPE_CHECKING:
@@ -222,3 +222,14 @@ def test_read_line_eof_at_the_beginning() -> None:
222
222
  read_line(fd=r)
223
223
  finally:
224
224
  os.close(r)
225
+
226
+
227
+ def test_backend_output_with_unencodable_path(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
228
+ monkeypatch.setenv("PYTHONIOENCODING", "ascii") # like a Windows ANSI code page that lacks a path character
229
+ root: Final[Path] = tmp_path / "pröject"
230
+ root.mkdir()
231
+ (root / "build_tester.py").write_text("def build_sdist(sdist_directory, config_settings=None): return 'out.tar.gz'")
232
+
233
+ result: Final = SubprocessFrontend(root, (root,), "build_tester", None, ()).build_sdist(root / "dist")
234
+
235
+ assert (result.sdist, "pr\\xf6ject" in result.out) == (root / "dist" / "out.tar.gz", True)
@@ -1,15 +1,19 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import pickle # ruff:ignore[suspicious-pickle-import]
3
4
  import re
4
5
  import subprocess # ruff:ignore[suspicious-subprocess-import]
5
6
  import sys
7
+ from concurrent.futures import ProcessPoolExecutor
8
+ from multiprocessing import get_context
6
9
  from pathlib import Path
7
10
  from textwrap import dedent
8
- from typing import TYPE_CHECKING, Final, Literal
11
+ from typing import TYPE_CHECKING, Any, Final, Literal
9
12
 
10
13
  import pytest
11
14
  from packaging.requirements import Requirement
12
15
 
16
+ from pyproject_api import _via_fresh_subprocess
13
17
  from pyproject_api._frontend import BackendFailed
14
18
  from pyproject_api._via_fresh_subprocess import SubprocessFrontend
15
19
 
@@ -55,6 +59,18 @@ def test_relative_project_folder(local_builder: Callable[[str], Path], monkeypat
55
59
  assert frontend.get_requires_for_build_wheel().requires == (Requirement("wheel"),)
56
60
 
57
61
 
62
+ @pytest.mark.skipif(sys.platform == "win32", reason="Windows drops trailing spaces from names")
63
+ def test_backend_path_with_trailing_space(tmp_path: Path) -> None: # pragma: win32 no cover
64
+ backend: Final = tmp_path / "backend "
65
+ backend.mkdir()
66
+ (backend / "build_tester.py").write_text(
67
+ "def get_requires_for_build_wheel(config_settings=None):\n return ['wheel']\n"
68
+ )
69
+ frontend: Final = SubprocessFrontend(tmp_path, (backend,), "build_tester", None, ())
70
+
71
+ assert frontend.get_requires_for_build_wheel().requires == (Requirement("wheel"),)
72
+
73
+
58
74
  @pytest.mark.parametrize(
59
75
  "hook",
60
76
  [
@@ -161,6 +177,39 @@ def test_large_command_with_failed_backend(local_builder: Callable[[str], Path])
161
177
  assert "RuntimeError: backend import failed" in context.value.err
162
178
 
163
179
 
180
+ @pytest.mark.parametrize(
181
+ "error_type",
182
+ [
183
+ pytest.param(KeyboardInterrupt, id="keyboard-interrupt"),
184
+ pytest.param(SystemExit, id="system-exit"),
185
+ pytest.param(RuntimeError, id="runtime-error"),
186
+ ],
187
+ )
188
+ def test_interrupted_frontend_cleans_up_backend(
189
+ error_type: type[BaseException], local_builder: Callable[[str], Path], mocker: pytest_mock.MockerFixture
190
+ ) -> None:
191
+ root: Final = local_builder("""
192
+ import time
193
+
194
+ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
195
+ time.sleep(60)
196
+ return "demo-1.0-py3-none-any.whl"
197
+ """)
198
+ status_factory: Final = mocker.spy(_via_fresh_subprocess, "SubprocessCmdStatus")
199
+ mocker.patch("pyproject_api._frontend.sleep", side_effect=error_type("build interrupted"))
200
+
201
+ try:
202
+ with pytest.raises(error_type):
203
+ SubprocessFrontend(*SubprocessFrontend.create_args_from_folder(root)[:-1]).build_wheel(root / "dist")
204
+
205
+ assert not status_factory.spy_return.is_alive()
206
+ finally:
207
+ # Keep a regression from leaving the backend and its non-daemon thread running.
208
+ status: Final = status_factory.spy_return
209
+ status.process.kill()
210
+ status.join(timeout=10)
211
+
212
+
164
213
  @pytest.mark.parametrize("cmd", ["build_wheel", "build_sdist"])
165
214
  def test_missing_required_cmd(cmd: str, local_builder: Callable[[str], Path]) -> None:
166
215
  tmp_path = local_builder("")
@@ -721,3 +770,46 @@ def test_backend_failed_str_repr() -> None:
721
770
 
722
771
  exc = BackendFailed({"code": 3, "exc_type": "Error", "exc_msg": "msg"}, "out\n", "err\n")
723
772
  assert str(exc) == "packaging backend failed (code=3), with Error: msg\nerr\nout"
773
+
774
+
775
+ @pytest.mark.parametrize("protocol", range(pickle.HIGHEST_PROTOCOL + 1))
776
+ @pytest.mark.parametrize("result", [{}, {"code": None}, {"code": 1, "exc_type": "TypeError", "exc_msg": "bad"}])
777
+ def test_backend_failed_pickle(protocol: int, result: dict[str, Any]) -> None:
778
+ exc = BackendFailed(result, "backend stdout", "backend stderr")
779
+ exc.add_note("building a wheel")
780
+ restored = pickle.loads( # ruff:ignore[suspicious-pickle-usage]
781
+ pickle.dumps(exc, protocol=protocol)
782
+ )
783
+
784
+ assert type(restored) is BackendFailed
785
+ assert restored.args == exc.args == ()
786
+ assert restored.__dict__ == exc.__dict__
787
+ assert str(restored) == str(exc)
788
+ assert repr(restored) == repr(exc)
789
+
790
+
791
+ def _build_wheel_in_process(root: Path) -> str:
792
+ frontend = SubprocessFrontend(*SubprocessFrontend.create_args_from_folder(root)[:-1])
793
+ return str(frontend.build_wheel(root / "dist").wheel)
794
+
795
+
796
+ def test_backend_failed_process_pool(local_builder: Callable[[str], Path]) -> None:
797
+ root = local_builder("""
798
+ import sys
799
+
800
+ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
801
+ print("backend stdout")
802
+ print("backend stderr", file=sys.stderr)
803
+ raise RuntimeError("build failed")
804
+ """)
805
+ with ProcessPoolExecutor(max_workers=1, mp_context=get_context("spawn")) as executor:
806
+ future = executor.submit(_build_wheel_in_process, root)
807
+ with pytest.raises(BackendFailed) as context:
808
+ future.result(timeout=30)
809
+ exc = context.value
810
+ assert exc.args == ()
811
+ assert exc.code == 1
812
+ assert exc.exc_type == "RuntimeError"
813
+ assert exc.exc_msg == "build failed"
814
+ assert "backend stdout" in exc.out
815
+ assert "backend stderr" in exc.err
@@ -1,27 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: "github-actions"
4
- directory: "/"
5
- labels:
6
- - dependencies
7
- - github_actions
8
- - skip news
9
- schedule:
10
- interval: "weekly"
11
- day: "tuesday"
12
- groups:
13
- github-actions:
14
- patterns:
15
- - "*"
16
- cooldown:
17
- default-days: 7
18
- - package-ecosystem: "pre-commit"
19
- directory: "/"
20
- labels:
21
- - dependencies
22
- - skip news
23
- schedule:
24
- interval: "weekly"
25
- day: "tuesday"
26
- cooldown:
27
- default-days: 7
File without changes
File without changes
File without changes