improve reliability of `poetry shell` configuring $PATH properly
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.
-  If an exception occurs when executing a command, I executed it again in debug mode (-vvvoption).
- OS version and name: macOS 10.14
- Poetry version: 0.11.5
Issue
From https://github.com/sdispater/poetry/issues/198#issuecomment-430742299.
Preface: I’m not sure if this can be realistically solved by Poetry or if you’re too much at the mercy of each person’s shell configuration. But here goes.
Certain shell configurations interact poorly with poetry shell; see https://github.com/sdispater/poetry/issues/198#issuecomment-424016403 and https://github.com/sdispater/poetry/issues/172 for examples. Resolutions to the issue tend to be ad-hoc workarounds that involve spelunking in your shell configuration, see https://github.com/sdispater/poetry/issues/198#issuecomment-430742299 and https://github.com/sdispater/poetry/issues/172#issuecomment-401554154 respectively.
The root of the issue seems to be that Poetry attaches the virtualenv to the beginning of $PATH, then spawns the shell, which may override that configuration by attaching more things to the beginning of $PATH. If possible, modifying $PATH after the shell initializes ought to give a better result that will work by default on more systems. I don’t recall seeing this issue with pipenv shell, but admittedly I didn’t dig as deep while I was using it as my primary tool.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:20
- Comments:9 (2 by maintainers)

 Top Related Medium Post
Top Related Medium Post Top Related StackOverflow Question
Top Related StackOverflow Question
I was curious about the inconsistency of this command so I followed the bread crumbs, the OP points the right reason, but here is my walkthrough, which may be useful:
TL;DR
don’t use
subprocess.call('/bin/bash')AFTER setting the venv variables, it will in fact inherit the environ but the child will run the rc files after, which may or may not overshadow relevant variables, depending on the user configurationinstead, do:
This can be done via
Popen, but a reliable and portable way is usingpexpect.spawn.sendlinefollowed bypexpect.spawn.interactExplanation
1. Chasing the source lines
1 -
poetry shellcallspoetry.console.mainwhich callsApplication().run(), which uses cleo’sBaseApplicationand wtv and finally gets to poetry.console.commands.shell.ShellCommand2 -
ShellCommand.handlerunsself.env.execute(Shell.get().path)Shell.get().pathis meant to return the path of the current-running shell binary, probably no problem there3 -
self.env.executeis the next stepself.envis created viaEnv.create_venv(self.poetry.file.parent, o, self.poetry.package.name)which createsVirtualEnvwhich finally contains theexecutemethod that is run:You can see it sets enviroment variables and calls
super().execute(which isEnv.executedefined in the same file)and there is the problem
2. Whats wrong?
The problem is that the environment variables are set before the shell process is created, which do inherit these variables, but can overshadow in its
.rcfiles execution startup-routine. This will be the case in every shell, maybe you’re lucky and your rc files does not overshadows the relevant variables, or maybe you can work around in your rc files to guard a$POETRY_SHELLconditional but that will always be unreliableHere’s how it works:
Now notices what happens if I spawn a new
bash:As any child process do, all environment variables are inherited, even my PROMPT (via $PS1) is still marked as in the virtualenv the result will be exactly the same if I had called bash via python’s subprocess.call:
In both cases, the rc files will be executed as they normally do every time a
bash|zsh|wtvprocess is initiaded, therefore, overshadowing the parent-inherited environment variables:Note that my prompt still inherited the parent $PS1, as I don’t have any PS1 setting in my
.bashrc, but I do have pyenv’s shims activation, which overshadows the venv binaries3. Solution
In short, the core problem can be reproduced in a fresh shell:
Ie, 1 - “run the source command”, 2 - “start interactive shell”,
What should be done is sending the command after the startup routines:
Note the resulted lines, it wasn’t me who typed the line
$ source /home/...it came from stdin, then the control came back to me viaexec </dev/ttyTurns out this is the same thing
pipenv shelldoesthe relevant lines are:
Ie, 1 - Create a interactive shell; 2 - queue the source command to be executed via stdin; 3 - bring subprocess interaction to user
Using pipenv aproach, this probably would do as an almost drop in replacement for the
subprocess.call:Then just change
subprocess.call([bin] + list(args), **kwargs)tospawn_venv(bin, self._path, args, kwargs)This is not good enough for a PR because:
you may want to set the
dimensionsargument in thespawncall and add a event handler for terminal resizing, pipenv uses a backport ofshutil.get_terminal_sizefor thatpipenv provides a cli flag that end’s up using subprocess.call normally
I don’t know which
**kwargscan be used, would need to normalize between subprocess.call and pexpect.spawnMaybe it breaks the simmetry between Env.execute and Env.run