poetry run does not relay exit code
See original GitHub issue- I am on the latest Poetry version.
- I have searched the issues of this repo and believe that this is not a duplicate.
- OS version and name: ArchLinux (ArchLabs) 5.6.7-arch1-1
- Poetry version: 1.0.5
- Link of a Gist with the contents of your pyproject.toml file: https://github.com/pawamoy/poetry-issue-2369/blob/master/pyproject.toml
Issue
Poetry does not relay the exit code of a script (as in from Poetry’s scripts
section) when ran with poetry run
.
To reproduce, run the following snippet or check the repo directly: https://github.com/pawamoy/poetry-issue-2369
$ git clone https://github.com/pawamoy/poetry-issue-2369
$ cd poetry-issue-2369
$ poetry install -v
$ poetry shell
$ poetry-issue-2369
$ echo $?
1
$ exit
$ poetry run poetry-issue-2369
$ echo $?
0
Additional information:
$ poetry run which poetry-issue-2369
/home/pawamoy/.cache/pypoetry/virtualenvs/poetry-issue-2369-Q6VvSue2-py3.8/bin/poetry-issue-2369
$ cat /home/pawamoy/.cache/pypoetry/virtualenvs/poetry-issue-2369-Q6VvSue2-py3.8/bin/poetry-issue-2369
#!/home/pawamoy/.cache/pypoetry/virtualenvs/poetry-issue-2369-Q6VvSue2-py3.8/bin/python
#EASY-INSTALL-ENTRY-SCRIPT: 'poetry-issue-2369','console_scripts','poetry-issue-2369'
__requires__ = 'poetry-issue-2369'
import re
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('poetry-issue-2369', 'console_scripts', 'poetry-issue-2369')()
)
Note how the installed script wraps the entry-point call into sys.exit(...)
.
It means that, as a best-practice, the entry-point itself should not use sys.exit(...)
.
My main function returns an integer, and it’s the __main__
module that wraps it in sys.exit(...)
.
This allows to run both the installed script with poetry-issue-2369
and the Python module with python -m poetry-issue-2369
seamlessly.
# cli.py
def main(args=None):
return 1
# __main__.py
import sys
from poetry_issue_2369.cli import main
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
Solution
It seems to be because this snippet does not wrap the last line in sys.exit(...)
:
cmd += [
"import sys; "
"from importlib import import_module; "
"sys.argv = {!r}; {}"
"import_module('{}').{}()".format(args, src_in_sys_path, module, callable_)
]
https://github.com/python-poetry/poetry/blob/master/poetry/console/commands/run.py#L42-L47
The solution would be to wrap it in sys.exit(...)
:
- "import_module('{}').{}()".format(args, src_in_sys_path, module, callable_)
+ "sys.exit(import_module('{}').{}())".format(args, src_in_sys_path, module, callable_)
Issue Analytics
- State:
- Created 3 years ago
- Reactions:15
- Comments:11 (2 by maintainers)
This should be fixed in the latest preview release (1.2.0b1) by https://github.com/python-poetry/poetry/pull/4456.
Care here for this problem. For me, this manifested when I converted a pre-commit hooks project from pip/setup to poetry:
Pip/Setup console_scripts do:
Poetry installed scripts do:
So, hooks entrys in .pre-comit-hooks.yml that used to fail, now don’t, because they all return int, and used to sys.exit, and now don’t.
In order to fix this, one could add sys.exit to the of then imported main(), but that means all python (not cli) consumers that call main() will get a hard sys exit, not just the returns int.
That then means, one must drop a separate script entry point, like hook(), that calls main() and calls sys.exit with its return. It’s all kind of awkword after moving from setup.py and expecting scripts to do the same thing.