diff --git a/pipenv/project.py b/pipenv/project.py index 59ba0619fe..c13cf59798 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -5,6 +5,7 @@ import re import sys import base64 +import fnmatch import hashlib import contoml from first import first @@ -33,6 +34,7 @@ safe_expandvars, is_star, get_workon_home, + is_virtual_environment, ) from .environments import ( PIPENV_MAX_DEPTH, @@ -273,21 +275,23 @@ def get_name(name, location): clean_name, encoded_hash = get_name(name, self.pipfile_location) venv_name = "{0}-{1}".format(clean_name, encoded_hash) - # This should work most of the time, for non-WIndows, in-project venv, - # or "proper" path casing (on Windows). + # This should work most of the time for + # Case-sensitive filesystems, + # In-project venv + # "Proper" path casing (on non-case-sensitive filesystems). if ( - os.name != "nt" + fnmatch.fnmatch('A', 'a') or self.is_venv_in_project() or self._get_virtualenv_location(venv_name) ): return clean_name, encoded_hash # Check for different capitalization of the same project. - from .patched.pew.pew import lsenvs - - for env in lsenvs(): + for path in get_workon_home().iterdir(): + if not is_virtual_environment(path): + continue try: - env_name, hash_ = env.rsplit("-", 1) + env_name, hash_ = path.name.rsplit("-", 1) except ValueError: continue if len(hash_) != 8 or env_name.lower() != name.lower(): diff --git a/pipenv/utils.py b/pipenv/utils.py index a490df7a57..74bb22875a 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -1310,7 +1310,6 @@ def fs_str(string): _fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() -# Duplicated from Pew to avoid importing it (performance considerations). def get_workon_home(): from ._compat import Path @@ -1323,3 +1322,19 @@ def get_workon_home(): os.environ.get("XDG_DATA_HOME", "~/.local/share"), "virtualenvs" ) return Path(os.path.expandvars(workon_home)).expanduser() + + +def is_virtual_environment(path): + """Check if a given path is a virtual environment's root. + + This is done by checking if the directory contains a Python executable in + its bin/Scripts directory. Not technically correct, but good enough for + general usage. + """ + if not path.is_dir(): + return False + for bindir_name in ('bin', 'Scripts'): + for python_like in path.joinpath(bindir_name).glob('python*'): + if python_like.is_file() and os.access(str(python_like), os.X_OK): + return True + return False diff --git a/setup.cfg b/setup.cfg index f502548fe8..c2f10f1727 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,4 +11,5 @@ ignore = # E231: missing whitespace after ',' # E402: module level import not at top of file # E501: line too long - E127,E128,E129,E222,E231,E402,E501 + # W503: line break before binary operator + E127,E128,E129,E222,E231,E402,E501,W503