Description
_resource_binary_path() returns the path yielded by importlib.resources.as_file() after leaving the context manager. For resources backed by a ZIP importer, that path is a temporary extraction which is deleted when the context exits. resolve_binary_path() then passes the expired path to _copy_to_cache(), where read_bytes() fails.
The cache copy appears to be the intended mechanism for non-filesystem package resources, but it currently happens too late.
Reproduction
The lifetime problem can be reproduced with any ZIP-backed package resource:
import importlib
import sys
import tempfile
import zipfile
from pathlib import Path
import importlib.resources as resources
with tempfile.TemporaryDirectory() as directory:
archive = Path(directory) / "package.zip"
with zipfile.ZipFile(archive, "w") as output:
output.writestr("example_package/__init__.py", "")
output.writestr("example_package/binary", b"binary")
sys.path.insert(0, str(archive))
importlib.invalidate_caches()
resource = resources.files("example_package").joinpath("binary")
with resources.as_file(resource) as extracted:
returned = extracted
print(returned.exists()) # True
print(returned.exists()) # False
Stagehand follows this exact pattern at src/stagehand/_custom/sea_binary.py:60-61, then attempts to read the returned path at line 73.
Expected behavior
The packaged binary should be copied into Stagehand's persistent cache while the as_file() context is still active, or the context lifetime should otherwise cover the copy.
Actual behavior
For a ZIP-backed Traversable, _resource_binary_path() returns a deleted temporary path and local-mode resolution fails before startup.
Why this matters
Normal wheel installs are usually unpacked, which hides the defect. ZIP imports, zipapps, and packaging/deployment systems that expose resources through a non-filesystem loader exercise the temporary-resource path that this code is intended to support.
Prior-art check
I searched open/closed issues and PRs for zipimport, importlib.resources.as_file, packaged resource lifetime, and _resource_binary_path and found no existing report.
Description
_resource_binary_path()returns the path yielded byimportlib.resources.as_file()after leaving the context manager. For resources backed by a ZIP importer, that path is a temporary extraction which is deleted when the context exits.resolve_binary_path()then passes the expired path to_copy_to_cache(), whereread_bytes()fails.The cache copy appears to be the intended mechanism for non-filesystem package resources, but it currently happens too late.
Reproduction
The lifetime problem can be reproduced with any ZIP-backed package resource:
Stagehand follows this exact pattern at
src/stagehand/_custom/sea_binary.py:60-61, then attempts to read the returned path at line 73.Expected behavior
The packaged binary should be copied into Stagehand's persistent cache while the
as_file()context is still active, or the context lifetime should otherwise cover the copy.Actual behavior
For a ZIP-backed
Traversable,_resource_binary_path()returns a deleted temporary path and local-mode resolution fails before startup.Why this matters
Normal wheel installs are usually unpacked, which hides the defect. ZIP imports, zipapps, and packaging/deployment systems that expose resources through a non-filesystem loader exercise the temporary-resource path that this code is intended to support.
Prior-art check
I searched open/closed issues and PRs for
zipimport,importlib.resources.as_file, packaged resource lifetime, and_resource_binary_pathand found no existing report.