From b10f1428259f97d913a2d71678b6aaf36bbeceb0 Mon Sep 17 00:00:00 2001 From: Akash Kumar <116457960+akashchamp@users.noreply.github.com> Date: Fri, 23 Oct 2026 02:44:12 +0530 Subject: [PATCH] fix: resolve the venv path so entrypoint shebangs are absolute A relative path passed to `poetry bundle venv` ended up in the shebangs of the bundled entrypoints, so they only worked from the original directory. --- .../console/commands/bundle/venv.py | 3 +- tests/console/commands/bundle/test_venv.py | 33 ++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/poetry_plugin_bundle/console/commands/bundle/venv.py b/src/poetry_plugin_bundle/console/commands/bundle/venv.py index 70eaf99..aa4508b 100644 --- a/src/poetry_plugin_bundle/console/commands/bundle/venv.py +++ b/src/poetry_plugin_bundle/console/commands/bundle/venv.py @@ -61,7 +61,8 @@ class BundleVenvCommand(BundleCommand): bundler_name = "venv" def configure_bundler(self, bundler: VenvBundler) -> None: # type: ignore[override] - bundler.set_path(Path(self.argument("path"))) + # resolve now, so entrypoint shebangs do not depend on the current directory + bundler.set_path(Path(self.argument("path")).resolve()) bundler.set_executable(self.option("python")) bundler.set_remove(self.option("clear")) bundler.set_compile(self.option("compile")) diff --git a/tests/console/commands/bundle/test_venv.py b/tests/console/commands/bundle/test_venv.py index 2f84d8d..dc48dbb 100644 --- a/tests/console/commands/bundle/test_venv.py +++ b/tests/console/commands/bundle/test_venv.py @@ -9,6 +9,8 @@ if TYPE_CHECKING: + import pytest + from cleo.testers.application_tester import ApplicationTester from pytest_mock import MockerFixture @@ -46,11 +48,11 @@ def test_venv_calls_venv_bundler( ] == mock.call_args_list assert set_path.call_args_list == [ - mocker.call(mocker.ANY, Path("/foo")), - mocker.call(mocker.ANY, Path("/foo")), - mocker.call(mocker.ANY, Path("/foo")), - mocker.call(mocker.ANY, Path("/foo")), - mocker.call(mocker.ANY, Path("/foo")), + mocker.call(mocker.ANY, Path("/foo").resolve()), + mocker.call(mocker.ANY, Path("/foo").resolve()), + mocker.call(mocker.ANY, Path("/foo").resolve()), + mocker.call(mocker.ANY, Path("/foo").resolve()), + mocker.call(mocker.ANY, Path("/foo").resolve()), ] assert set_executable.call_args_list == [ mocker.call(mocker.ANY, None), @@ -81,3 +83,24 @@ def test_venv_calls_venv_bundler( mocker.call(mocker.ANY, False), mocker.call(mocker.ANY, True), ] + + +def test_venv_resolves_relative_path( + app_tester: ApplicationTester, + mocker: MockerFixture, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + mocker.patch( + "poetry_plugin_bundle.bundlers.venv_bundler.VenvBundler.bundle", + return_value=True, + ) + set_path = mocker.spy(VenvBundler, "set_path") + monkeypatch.chdir(tmp_path) + + app_tester.application.catch_exceptions(False) + assert app_tester.execute("bundle venv ../bundle") == 0 + + assert set_path.call_args_list == [ + mocker.call(mocker.ANY, (tmp_path.parent / "bundle").resolve()) + ]