Skip to content

Commit c1af4d8

Browse files
authored
Merge pull request #33 from Joshix-1/multiprocessing-fix
Only delete zipapps cache on the main process
2 parents a94c3d1 + 3f8c60a commit c1af4d8

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

test_utils.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,55 @@ def test_uvx_zipapps():
791791
assert b"app.pyz" in output, output.decode("utf-8", "replace")
792792

793793

794+
if hasattr(os, "fork"):
795+
def test_multiprocessing():
796+
"""
797+
Test deleting the cache with a multiprocessing app.
798+
799+
When the app forks, the cache directory should only be cleared if the main process exits.
800+
"""
801+
_clean_paths(root=False)
802+
803+
secret = "XXXXXXXXXXXXX"
804+
unzip_path = (test_path / "multiprocessing_test" / "cache").absolute()
805+
806+
Path("test.so").touch()
807+
808+
mock_main = Path("mock_main.py")
809+
mock_main.touch()
810+
mock_main.write_text(
811+
f"def main():\n"
812+
f" import os, sys, os.path\n"
813+
f" is_parent = os.fork()\n"
814+
f" print({secret!r}, file=sys.stderr if is_parent else sys.stdout)\n"
815+
f" if not is_parent: return\n"
816+
f" os.waitpid(is_parent, 0)\n"
817+
f" print(os.path.isdir({str(unzip_path)!r}))\n"
818+
)
819+
app_path = create_app(
820+
includes="mock_main.py",
821+
main="mock_main:main",
822+
unzip="test.so",
823+
clear_zipapps_cache=True,
824+
unzip_path=str(unzip_path),
825+
)
826+
stdout_output, stderr_output = subprocess.Popen(
827+
[sys.executable, str(app_path)],
828+
stderr=subprocess.PIPE,
829+
stdout=subprocess.PIPE,
830+
text=True,
831+
).communicate()
832+
833+
assert not unzip_path.exists(), "Cache dir should be deleted"
834+
835+
secret += "\n"
836+
# Test that the child printed the string successfully and no errors got raised
837+
assert stderr_output == secret, f"unexpected stderr: {stderr_output!r}"
838+
# Test that the main process prints the string sucessfully
839+
# and that the cache directory still exists after the child exits
840+
assert stdout_output == (secret + "True\n"), f"unexpected stdout: {stdout_output!r}"
841+
842+
794843
def main():
795844
"""
796845
test all cases

zipapps/ensure_zipapps.py.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,11 @@ def prepare_path():
141141
if clear_zipapps_cache:
142142
import atexit
143143

144+
main_pid = os.getpid()
145+
144146
def _remove_cache_folder():
147+
if main_pid != os.getpid():
148+
return # only remove folders when the main process exits
145149
rm_dir_or_file(_cache_folder_path)
146150
if not any(_cache_folder_path_parent.iterdir()):
147151
rm_dir_or_file(_cache_folder_path_parent)

0 commit comments

Comments
 (0)