Pipenv: `pipenv shell` fails with path including spaces.

Created on 23 Jan 2017  路  9Comments  路  Source: pypa/pipenv

tsbertalan@sindri:~$ sudo pip install pipenv
... snip ...
tsbertalan@sindri:~$ cd dirname\ with\ spaces/
tsbertalan@sindri:~/dirname with spaces$ pipenv shell
Creating a Pipfile for this project...
Creating a virtualenv for this project...
New python executable in /home/tsbertalan/dirname with spaces/.venv/bin/python
Installing setuptools, pip, wheel...done.

Virtualenv location: /home/tsbertalan/dirname with spaces/.venv
Spawning environment shell (/bin/bash).
/bin/bash: /home/tsbertalan/dirname: No such file or directory
tsbertalan@sindri:~$ cd dirname\ with\ spaces/
tsbertalan@sindri:~/dirname with spaces$ pipenv shell
Creating a Pipfile for this project...
Creating a virtualenv for this project...
New python executable in /home/tsbertalan/dirname with spaces/.venv/bin/python
Installing setuptools, pip, wheel...done.

Virtualenv location: /home/tsbertalan/dirname with spaces/.venv
Spawning environment shell (/bin/bash).
/bin/bash: /home/tsbertalan/dirname: No such file or directory
Type help wanted

Most helpful comment

I'm going to leave this here for when someone eventually searches trying to solve this issue. While #99 solves the pipenv activation issue, most other pipenv commands still don't work properly. After a couple hours of pulling threads, I came across this.

virtualenv, and thus pipenv, calls the absolute path to the .venv directory to run things like pip and python. Since these have a space in their path, the the linux exec call will always treat the first space it encounters as the end of the command. Anything after that is considered a parameter. This means anything in the form /home/user/path to dir/.venv/bin/pip won't work.

So in order to address this, we'd need to allow the user to provide an alternative path for installing the virtualenv and then track that somewhere. That seems a bit excessive for a likely uncommon, and fairly avoidable, edge case. If it proves to be a significant problem, that's probably the best route to go though. Until then, I don't think we can support paths with spaces in a meaningful way.

All 9 comments

Okay, so I've developed a naive solution, but I'm just looking for input on this. In cli.py, on lines 276-279 (at the time of writing), we have this:

if source:
    return 'source {0}/bin/activate{1}'.format(project.virtualenv_location, suffix)
else:
    return '{0}/bin/activate'.format(project.virtualenv_location)

Simply replacing the block with the following enables proper functionality by escaping the spaces:

venv_location = project.virtualenv_location.replace(' ', '\ ')

if source:
    return 'source {0}/bin/activate{1}'.format(venv_location, suffix)
else:
    return '{0}/bin/activate'.format(venv_location)

@kimtree had suggested elsewhere that I instead use encoded string escaping, e.g. str_variable.encode('string-escape'). Unfortunately I'm a little behind on all this encoding stuff, so I'm just looking on feedback as to which method would be preferable and I can submit a pull request. My only concern with this is possible compatibility issues between 2 and 3.

I have a possible alternative solution. Using os.path.join instead of os.sep.join in project.py lines 48 and 52 (currently), might produce correct pathing.

I would have tested it myself but I don't seem to be able to run a self built version of pipenv.

@kfirbreger unfortunately, that has the same problem as os.sep.join. It's concatenating a list
['', 'home', 'tsbertalan', 'dirname with spaces'] with os.sep. When this path is passed to bash, bash can't differentiate between a path with spaces and a new parameter.

@jessebraham, I think you're on the right track. encode('string-escape') appears to only work in Python 2 and doesn't escape spaces like we'd like. That means the replace(' ', '\ ') route is probably the right way to go, but there are often unforeseen side effects with brute forcing these things. Since pipenv doesn't currently support Windows though, it's probably safe. So, I believe that means I'm +1 on your initial proposal.

If @kennethreitz is in agreement, would you be interested in providing a PR to fix this? The only tweak that I think might be helpful is implementing the conversion at the source in project.py.

i'm all for a fix!

Ask and you shall receive 馃槈

I'm going to leave this here for when someone eventually searches trying to solve this issue. While #99 solves the pipenv activation issue, most other pipenv commands still don't work properly. After a couple hours of pulling threads, I came across this.

virtualenv, and thus pipenv, calls the absolute path to the .venv directory to run things like pip and python. Since these have a space in their path, the the linux exec call will always treat the first space it encounters as the end of the command. Anything after that is considered a parameter. This means anything in the form /home/user/path to dir/.venv/bin/pip won't work.

So in order to address this, we'd need to allow the user to provide an alternative path for installing the virtualenv and then track that somewhere. That seems a bit excessive for a likely uncommon, and fairly avoidable, edge case. If it proves to be a significant problem, that's probably the best route to go though. Until then, I don't think we can support paths with spaces in a meaningful way.

I would also like to add that the solution currently used probably will not work windows machines, as powershell, I believe, uses a different character to escape spaces in paths. It might be worth switching to Pathlib, which was introduces in Python 3.4

@kfirbreger At this point Windows is not officially supported, so it was not something that was taken in to consideration. If Windows support is added then yes it will need to be changed.

@nateprewitt thanks for the note above. I hit this today with a PIPENV_VENV_IN_PROJECT and it took some doing to find the solution as the current error message (FileNotFoundError: [Errno 2] No such file or directory) is only loosely correlated with an appropriate solution to the problem.

I guess if this is considered a fairly avoidable edge case, at the very least a warning during pipenv .venv creation that the .venv path is invalid due to the spaces would go a long way toward users being able to fairly avoid it, without having to dig into the details of correctly escaping path spaces per os. If I can come up with an acceptable test to issue the warning I'll send through a PR.

Thanks for considering!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xi picture xi  路  3Comments

jerzyk picture jerzyk  路  3Comments

bgjelstrup picture bgjelstrup  路  3Comments

ipmb picture ipmb  路  3Comments

leileigong picture leileigong  路  3Comments