Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect sys.argv[0] path when calling project scripts #6737

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7273f41
fix: RunCommand calling scripts with incorrect executable path
chdsbd Mar 31, 2019
9173580
Python 2 compatibility
chdsbd Mar 31, 2019
6209264
Add basic test
chdsbd Mar 31, 2019
399ed6d
doc
chdsbd Mar 31, 2019
1a915a9
Rewrite test to run project script
wagnerluis1982 Oct 7, 2022
121e42f
simplify code
wagnerluis1982 Oct 7, 2022
85174c7
fix type on RunCommand.run_script
wagnerluis1982 Oct 7, 2022
ee4a2a7
fix test for windows platform
wagnerluis1982 Oct 7, 2022
fd4cee7
replace comments for a nice docstring
wagnerluis1982 Oct 8, 2022
c925e39
rename Env.{_bin => get_bin_path}
wagnerluis1982 Oct 8, 2022
7ae7d32
Merge remote-tracking branch 'origin/master' into fix-incorrect-execu…
wagnerluis1982 Jan 11, 2023
4c919b8
rename test method
wagnerluis1982 Jan 11, 2023
81232c0
Merge branch 'master' into fix-incorrect-executable-path
wagnerluis1982 Jan 12, 2023
c761cfe
improve test readability
wagnerluis1982 Jan 15, 2023
e0e01eb
Merge branch 'master' into fix-incorrect-executable-path
wagnerluis1982 Jan 15, 2023
c1d579f
rewrite test assertion
wagnerluis1982 Jan 15, 2023
74b725e
Merge branch 'master' into fix-incorrect-executable-path
wagnerluis1982 Jan 16, 2023
0846cd6
Merge branch 'master' into fix-incorrect-executable-path
wagnerluis1982 Jan 18, 2023
02c9919
Merge branch 'master' into fix-incorrect-executable-path
wagnerluis1982 Jan 20, 2023
e4de1a4
use script_dirs instead of bin_path, make test more realistic
radoering Jan 21, 2023
2bdc670
add script extension ".cmd" when on windows
wagnerluis1982 Jan 21, 2023
713a1de
Merge branch 'master' into fix-incorrect-executable-path
wagnerluis1982 Jan 21, 2023
a758197
do not change args list
wagnerluis1982 Jan 22, 2023
bf6c3ca
Merge branch 'master' into fix-incorrect-executable-path
wagnerluis1982 Jan 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/poetry/console/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,19 @@ def _module(self) -> Module:

return module

def run_script(self, script: str | dict[str, str], args: str) -> int:
def run_script(self, script: str | dict[str, str], args: list[str]) -> int:
"""Runs an entry point script defined in the section ``[tool.poetry.scripts]``.

When a script exists in the venv bin folder, i.e. after ``poetry install``,
then ``sys.argv[0]`` must be set to the full path of the executable, so
``poetry run foo`` and ``poetry shell``, ``foo`` have the same ``sys.argv[0]``
that points to the full path.

Otherwise (when an entry point script does not exist), ``sys.argv[0]`` is the
script name only, i.e. ``poetry run foo`` has ``sys.argv == ['foo']``.
"""
args = [self.env.get_bin_path(args[0]), *args[1:]]

if isinstance(script, dict):
script = script["callable"]

Expand Down
12 changes: 6 additions & 6 deletions src/poetry/utils/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -1281,7 +1281,7 @@ def python(self) -> str:
"""
Path to current python executable
"""
return self._bin(self._executable)
return self.get_bin_path(self._executable)

@property
def marker_env(self) -> dict[str, Any]:
Expand Down Expand Up @@ -1349,7 +1349,7 @@ def pip(self) -> str:
"""
# we do not use as_posix() here due to issues with windows pathlib2
# implementation
path = self._bin(self._pip_executable)
path = self.get_bin_path(self._pip_executable)
if not Path(path).exists():
return str(self.pip_embedded)
return path
Expand Down Expand Up @@ -1459,7 +1459,7 @@ def get_marker_env(self) -> dict[str, Any]:
raise NotImplementedError()

def get_pip_command(self, embedded: bool = False) -> list[str]:
if embedded or not Path(self._bin(self._pip_executable)).exists():
if embedded or not Path(self.get_bin_path(self._pip_executable)).exists():
return [self.python, self.pip_embedded]
# run as module so that pip can update itself on Windows
return [self.python, "-m", "pip"]
Expand Down Expand Up @@ -1489,7 +1489,7 @@ def get_command_from_bin(self, bin: str) -> list[str]:
# embedded pip when pip is not available in the environment
return self.get_pip_command()

return [self._bin(bin)]
return [self.get_bin_path(bin)]

def run(self, bin: str, *args: str, **kwargs: Any) -> str | int:
cmd = self.get_command_from_bin(bin) + list(args)
Expand Down Expand Up @@ -1571,7 +1571,7 @@ def script_dirs(self) -> list[Path]:
self._script_dirs.append(self.userbase / self._script_dirs[0].name)
return self._script_dirs

def _bin(self, bin: str) -> str:
def get_bin_path(self, bin: str) -> str:
"""
Return path to the given executable.
"""
Expand Down Expand Up @@ -1930,7 +1930,7 @@ def execute(self, bin: str, *args: str, **kwargs: Any) -> int:
return super().execute(bin, *args, **kwargs)
return 0

def _bin(self, bin: str) -> str:
def get_bin_path(self, bin: str) -> str:
return bin


Expand Down
37 changes: 37 additions & 0 deletions tests/console/commands/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import subprocess

from pathlib import Path
from typing import TYPE_CHECKING

import pytest

from poetry.factory import Factory
from poetry.utils._compat import WINDOWS


Expand Down Expand Up @@ -146,3 +148,38 @@ def test_run_script_exit_code(
)
assert tester.execute("exit-code") == 42
assert tester.execute("return-code") == 42


@pytest.mark.parametrize(
"installed_script", [False, True], ids=["not installed", "installed"]
)
def test_run_project_script_sys_argv0(
installed_script: bool,
mocker: MockerFixture,
tmp_venv: VirtualEnv,
command_tester_factory: CommandTesterFactory,
):
"""
If RunCommand calls an installed script defined in pyproject.toml, sys.argv[0]
must be set to the full path of the script.
"""
cli_script = "foo"

if installed_script:
if WINDOWS:
cli_script += ".exe"
cli_script = tmp_venv._bin_dir / cli_script
cli_script.touch()
if WINDOWS:
cli_script = str(cli_script).replace("\\", "\\\\")
wagnerluis1982 marked this conversation as resolved.
Show resolved Hide resolved

poetry = Factory().create_poetry(
Path(__file__).parent.parent.parent / "fixtures" / "simple_project"
)
env_execute_mock = mocker.patch("poetry.utils.env.Env.execute", return_value=0)
tester = command_tester_factory("run", poetry, environment=tmp_venv)

tester.execute("foo status")

expected_sys_argv = f"sys.argv = ['{cli_script}', 'status']"
assert expected_sys_argv in env_execute_mock.call_args_list[0][0][2]
wagnerluis1982 marked this conversation as resolved.
Show resolved Hide resolved