Skip to content

Commit f29bb73

Browse files
committed
Account for macOS framework launcher paths in venv regression
Identify the installed framework launcher by build configuration and file identity, then retain exact path assertions for launcher presets and directory canonicalization. Keep all cases and the production resolver unchanged. Assisted-by: OpenAI Codex:model identifier unavailable
1 parent 68ea941 commit f29bb73

1 file changed

Lines changed: 27 additions & 10 deletions

File tree

‎extra_tests/snippets/stdlib_sys.py‎

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,19 @@ def test_getframemodulename():
184184
with tempfile.TemporaryDirectory() as directory:
185185
root = Path(directory).resolve()
186186
interpreter = Path(sys.executable).resolve()
187+
# A framework build can also run its embedded app directly. Match the
188+
# installed launcher's file identity before applying launcher semantics.
189+
framework_base = (
190+
Path(sys.base_prefix)
191+
/ "bin"
192+
/ f"python{sys.version_info.major}.{sys.version_info.minor}"
193+
)
194+
framework_launcher = (
195+
sys.platform == "darwin"
196+
and bool(getattr(sys, "_framework", ""))
197+
and framework_base.is_file()
198+
and interpreter.samefile(framework_base)
199+
)
187200
home = root / "home"
188201
home.mkdir()
189202
venv_env = dict(os.environ)
@@ -227,46 +240,50 @@ def executable_paths(executable, *, cwd=None, env=venv_env):
227240
invocation = f"./bin/{kind}" if kind == "relative" else executable
228241
assert executable_paths(invocation, cwd=bin_dir.parent) == [
229242
str(executable),
230-
str(interpreter),
243+
str(framework_base if framework_launcher else interpreter),
231244
str(prefix),
232245
]
233246

234-
# Without a venv, preserve the invoked symlink for both executable fields.
247+
# Framework launchers preset their base; ordinary binaries keep argv[0].
235248
plain = root / "plain" / "python"
236249
plain.parent.mkdir()
237250
plain.symlink_to(interpreter)
238-
assert executable_paths(plain)[:2] == [str(plain), str(plain)]
251+
assert executable_paths(plain)[:2] == [
252+
str(plain),
253+
str(framework_base if framework_launcher else plain),
254+
]
239255

240-
# A copied executable still falls back to home/<invoked name>.
256+
# Without a launcher preset, copies fall back to home/<invoked name>.
241257
copied = root / "copied" / "python"
242258
copied.parent.mkdir()
243259
shutil.copy2(interpreter, copied)
244260
(home / copied.name).touch()
245261
(copied.parent / "pyvenv.cfg").write_text(f"home = {home}\n")
246262
assert executable_paths(copied) == [
247263
str(copied),
248-
str(home / copied.name),
264+
str(framework_base if framework_launcher else home / copied.name),
249265
str(copied.parent),
250266
]
251267

252268
# A directory alias does not turn a copied executable into a symlink.
253269
directory_alias = root / "directory-alias"
254270
directory_alias.symlink_to(copied.parent, target_is_directory=True)
255271
aliased_copy = directory_alias / copied.name
272+
# The framework launcher canonicalizes its directory before dispatch.
256273
assert executable_paths(aliased_copy) == [
257-
str(aliased_copy),
258-
str(home / copied.name),
259-
str(directory_alias),
274+
str(copied if framework_launcher else aliased_copy),
275+
str(framework_base if framework_launcher else home / copied.name),
276+
str(copied.parent if framework_launcher else directory_alias),
260277
]
261278

262-
# Resolving a final-component link must preserve aliases in its target.
279+
# Without a launcher preset, final-link resolution preserves target aliases.
263280
target_link = root / "linked" / "python"
264281
target_link.parent.mkdir()
265282
(target_link.parent / "pyvenv.cfg").write_text(f"home = {home}\n")
266283
target_link.symlink_to("../directory-alias/python")
267284
assert executable_paths(target_link) == [
268285
str(target_link),
269-
str(aliased_copy),
286+
str(framework_base if framework_launcher else aliased_copy),
270287
str(target_link.parent),
271288
]
272289

0 commit comments

Comments
 (0)