Skip to content

Commit d9eeafc

Browse files
committed
Correct cross-platform venv path handling (#310)
Corrects for changes in Python 3.14's handling of sysconfig._init_config_vars(), ensuring that cross-platform virtual environments have correct include paths.
1 parent b65dbf5 commit d9eeafc

File tree

4 files changed

+178
-20
lines changed

4 files changed

+178
-20
lines changed

.github/workflows/ci.yaml

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
strategy:
9090
fail-fast: false
9191
matrix:
92-
target: ['macOS', 'iOS', 'tvOS', 'watchOS', 'visionOS']
92+
platform: ['macOS', 'iOS', 'tvOS', 'watchOS', 'visionOS']
9393

9494
steps:
9595
- uses: actions/[email protected]
@@ -104,29 +104,29 @@ jobs:
104104
# It's an edge case, but when a new alpha is released, we need to use it ASAP.
105105
check-latest: true
106106

107-
- name: Build ${{ matrix.target }}
107+
- name: Build ${{ matrix.platform }}
108108
run: |
109-
# Do the build for the requested target.
110-
make ${{ matrix.target }} BUILD_NUMBER=${{ needs.config.outputs.BUILD_NUMBER }}
109+
# Do the build for the requested platform.
110+
make ${{ matrix.platform }} BUILD_NUMBER=${{ needs.config.outputs.BUILD_NUMBER }}
111111
112112
- name: Upload build artefacts
113113
uses: actions/[email protected]
114114
with:
115-
name: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
116-
path: dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
115+
name: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
116+
path: dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
117117

118118
briefcase-testbed:
119-
name: Briefcase testbed (${{ matrix.target }})
119+
name: Briefcase testbed (${{ matrix.platform }})
120120
runs-on: macOS-latest
121121
needs: [ config, build ]
122122
strategy:
123123
fail-fast: false
124124
matrix:
125-
target: ["macOS", "iOS"]
125+
platform: ["macOS", "iOS"]
126126
include:
127127
- briefcase-run-args:
128128

129-
- target: iOS
129+
- platform: iOS
130130
briefcase-run-args: ' -d "iPhone SE (3rd generation)"'
131131

132132
steps:
@@ -135,7 +135,7 @@ jobs:
135135
- name: Get build artifact
136136
uses: actions/[email protected]
137137
with:
138-
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
138+
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
139139
path: dist
140140
merge-multiple: true
141141

@@ -162,24 +162,24 @@ jobs:
162162
- name: Run support testbed check
163163
timeout-minutes: 10
164164
working-directory: Python-support-testbed
165-
run: briefcase run ${{ matrix.target }} Xcode --test ${{ matrix.briefcase-run-args }} -C support_package=\'../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz\'
165+
run: briefcase run ${{ matrix.platform }} Xcode --test ${{ matrix.briefcase-run-args }} -C support_package=\'../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz\'
166166

167167
cpython-testbed:
168-
name: CPython testbed (${{ matrix.target }})
168+
name: CPython testbed (${{ matrix.platform }})
169169
runs-on: macOS-latest
170170
needs: [ config, build ]
171171
strategy:
172172
fail-fast: false
173173
matrix:
174-
target: ["iOS", "visionOS"]
174+
platform: ["iOS", "visionOS"]
175175

176176
steps:
177177
- uses: actions/[email protected]
178178

179179
- name: Get build artifact
180180
uses: actions/[email protected]
181181
with:
182-
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
182+
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
183183
path: dist
184184
merge-multiple: true
185185

@@ -195,13 +195,13 @@ jobs:
195195

196196
- name: Unpack support package
197197
run: |
198-
mkdir support
199-
cd support
200-
tar zxvf ../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
198+
mkdir -p support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
199+
cd support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
200+
tar zxvf ../../../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
201201
202202
- name: Run CPython testbed
203203
timeout-minutes: 10
204-
working-directory: support
204+
working-directory: support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
205205
run: |
206206
# Run a representative subset of CPython core tests:
207207
# - test_builtin as a test of core language tools
@@ -210,3 +210,66 @@ jobs:
210210
# - test_bz2 as a simple test of third party libraries
211211
# - test_ctypes as a test of FFI
212212
python -m testbed run -- test --single-process --rerun -W test_builtin test_grammar test_os test_bz2 test_ctypes
213+
214+
crossenv-test:
215+
name: Cross-platform env test (${{ matrix.multiarch }})
216+
runs-on: macOS-latest
217+
needs: [ config, build ]
218+
strategy:
219+
fail-fast: false
220+
matrix:
221+
include:
222+
- platform: iOS
223+
slice: ios-arm64_x86_64-simulator
224+
multiarch: arm64-iphonesimulator
225+
- platform: iOS
226+
slice: ios-arm64_x86_64-simulator
227+
multiarch: x86_64-iphonesimulator
228+
- platform: iOS
229+
slice: ios-arm64
230+
multiarch: arm64-iphoneos
231+
232+
steps:
233+
- uses: actions/[email protected]
234+
235+
- name: Get build artifact
236+
uses: actions/[email protected]
237+
with:
238+
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
239+
path: dist
240+
merge-multiple: true
241+
242+
- name: Set up Python
243+
uses: actions/[email protected]
244+
with:
245+
# Appending -dev ensures that we can always build the dev release.
246+
# It's a no-op for versions that have been published.
247+
python-version: ${{ needs.config.outputs.PYTHON_VER }}-dev
248+
# Ensure that we *always* use the latest build, not a cached version.
249+
# It's an edge case, but when a new alpha is released, we need to use it ASAP.
250+
check-latest: true
251+
252+
- name: Unpack support package
253+
run: |
254+
mkdir -p support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
255+
cd support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
256+
tar zxvf ../../../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
257+
258+
- name: Run cross-platform environment test
259+
env:
260+
PYTHON_CROSS_PLATFORM: ${{ matrix.platform }}
261+
PYTHON_CROSS_SLICE: ${{ matrix.slice }}
262+
PYTHON_CROSS_MULTIARCH: ${{ matrix.multiarch }}
263+
run: |
264+
# Create and activate a native virtual environment
265+
python${{ needs.config.outputs.PYTHON_VER }} -m venv cross-venv
266+
source cross-venv/bin/activate
267+
268+
# Install pytest
269+
python -m pip install pytest
270+
271+
# Convert venv into cross-venv
272+
python support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}/Python.xcframework/${{ matrix.slice }}/platform-config/${{ matrix.multiarch }}/make_cross_venv.py cross-venv
273+
274+
# Run the test suite
275+
python -m pytest tests

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ tests/testbed/iOS
1515
*.log
1616
*.gz
1717
*.DS_Store
18+
cross-venv/
19+
temp

patch/Python/_cross_target.py.tmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import sysconfig
1111
sys.cross_compiling = True
1212
sys.platform = "{{platform}}"
1313
sys.implementation._multiarch = "{{arch}}-{{sdk}}"
14-
sys.base_prefix = sysconfig.get_config_var("prefix")
15-
sys.base_exec_prefix = sysconfig.get_config_var("prefix")
14+
sys.base_prefix = sysconfig._get_sysconfigdata()["prefix"]
15+
sys.base_exec_prefix = sysconfig._get_sysconfigdata()["prefix"]
1616

1717
###########################################################################
1818
# subprocess module patches

tests/test_cross_env.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import os
2+
import platform
3+
import sys
4+
import sysconfig
5+
from pathlib import Path
6+
7+
import pytest
8+
9+
# To run these tests, the following three environment variables must be set,
10+
# reflecting the cross-platform environment that is in effect.'
11+
PYTHON_CROSS_PLATFORM = os.getenv("PYTHON_CROSS_PLATFORM", "unknown")
12+
PYTHON_CROSS_SLICE = os.getenv("PYTHON_CROSS_SLICE", "unknown")
13+
PYTHON_CROSS_MULTIARCH = os.getenv("PYTHON_CROSS_MULTIARCH", "unknown")
14+
15+
# Determine some file system anchor points for the tests
16+
# Assumes that the tests are run in a virtual environment named
17+
# `cross-venv`,
18+
VENV_PREFIX = Path(__file__).parent.parent / "cross-venv"
19+
default_support_base = f"support/{sys.version_info.major}.{sys.version_info.minor}/{PYTHON_CROSS_PLATFORM}"
20+
SUPPORT_PREFIX = (
21+
Path(__file__).parent.parent
22+
/ os.getenv("PYTHON_SUPPORT_BASE", default_support_base)
23+
/ "Python.xcframework"
24+
/ PYTHON_CROSS_SLICE
25+
)
26+
27+
28+
###########################################################################
29+
# sys
30+
###########################################################################
31+
32+
def test_sys_platform():
33+
assert sys.platform == PYTHON_CROSS_PLATFORM.lower()
34+
35+
36+
def test_sys_cross_compiling():
37+
assert sys.cross_compiling
38+
39+
40+
def test_sys_multiarch():
41+
assert sys.implementation._multiarch == PYTHON_CROSS_MULTIARCH
42+
43+
44+
def test_sys_base_prefix():
45+
assert Path(sys.base_prefix) == SUPPORT_PREFIX
46+
47+
48+
def test_sys_base_exec_prefix():
49+
assert Path(sys.base_exec_prefix) == SUPPORT_PREFIX
50+
51+
52+
###########################################################################
53+
# platform
54+
###########################################################################
55+
56+
def test_platform_system():
57+
assert platform.system() == PYTHON_CROSS_PLATFORM
58+
59+
60+
###########################################################################
61+
# sysconfig
62+
###########################################################################
63+
64+
def test_sysconfig_get_platform():
65+
parts = sysconfig.get_platform().split("-", 2)
66+
assert parts[0] == PYTHON_CROSS_PLATFORM.lower()
67+
assert parts[2] == PYTHON_CROSS_MULTIARCH
68+
69+
70+
def test_sysconfig_get_sysconfigdata_name():
71+
parts = sysconfig._get_sysconfigdata_name().split("_", 4)
72+
assert parts[3] == PYTHON_CROSS_PLATFORM.lower()
73+
assert parts[4] == PYTHON_CROSS_MULTIARCH
74+
75+
76+
@pytest.mark.parametrize(
77+
"name, prefix",
78+
[
79+
# Paths that should be relative to the support folder
80+
("stdlib", SUPPORT_PREFIX),
81+
("include", SUPPORT_PREFIX),
82+
("platinclude", SUPPORT_PREFIX),
83+
("stdlib", SUPPORT_PREFIX),
84+
# paths that should be relative to the venv
85+
("platstdlib", VENV_PREFIX),
86+
("purelib", VENV_PREFIX),
87+
("platlib", VENV_PREFIX),
88+
("scripts", VENV_PREFIX),
89+
("data", VENV_PREFIX),
90+
]
91+
)
92+
def test_sysconfig_get_paths(name, prefix):
93+
assert sysconfig.get_paths()[name].startswith(str(prefix))

0 commit comments

Comments
 (0)