diff --git a/news/2849.bugfix b/news/2849.bugfix new file mode 100644 index 0000000000..65fda3e3fa --- /dev/null +++ b/news/2849.bugfix @@ -0,0 +1 @@ +Fixed a bug in ``pipenv clean`` which caused global packages to sometimes be inadvertently targeted for cleanup. diff --git a/pipenv/core.py b/pipenv/core.py index cc4ba51f05..5a1a997960 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -2327,8 +2327,6 @@ def do_check( def do_graph(bare=False, json=False, json_tree=False, reverse=False): import pipdeptree - - try: python_path = which("python") except AttributeError: @@ -2390,7 +2388,7 @@ def do_graph(bare=False, json=False, json_tree=False, reverse=False): err=True, ) sys.exit(1) - cmd = '"{0}" {1} {2}'.format( + cmd = '"{0}" {1} {2} -l'.format( python_path, escape_grouped_arguments(pipdeptree.__file__.rstrip("cdo")), flag ) # Run dep-tree. diff --git a/pipenv/project.py b/pipenv/project.py index 0722619f1d..1a371fdae5 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -9,6 +9,7 @@ import hashlib import contoml from first import first +from cached_property import cached_property import pipfile import pipfile.api import six @@ -279,26 +280,44 @@ def get_location_for_virtualenv(self): return vistir.compat.Path(name).absolute().as_posix() return str(get_workon_home().joinpath(name)) - def get_installed_packages(self): - from . import PIPENV_ROOT, PIPENV_VENDOR, PIPENV_PATCHED - from .utils import temp_path, load_path, temp_environ + @property + def working_set(self): + from .utils import load_path + sys_path = load_path(self.which("python")) + import pkg_resources + return pkg_resources.WorkingSet(sys_path) + + def find_egg(self, egg_dist): + import site + from distutils import sysconfig as distutils_sysconfig + site_packages = distutils_sysconfig.get_python_lib() + search_filename = "{0}.egg-link".format(egg_dist.project_name) + try: + user_site = site.getusersitepackages() + except AttributeError: + user_site = site.USER_SITE + search_locations = [site_packages, user_site] + for site_directory in search_locations: + egg = os.path.join(site_directory, search_filename) + if os.path.isfile(egg): + return egg + + def locate_dist(self, dist): + location = self.find_egg(dist) + if not location: + return dist.location + def get_installed_packages(self): + workingset = self.working_set + prefix = _normalized(self.env_paths["prefix"]) if self.virtualenv_exists: - with temp_path(), temp_environ(): - new_path = load_path(self.which("python")) - new_path = [ - new_path[0], - PIPENV_ROOT, - PIPENV_PATCHED, - PIPENV_VENDOR, - ] + new_path[1:] - sys.path = new_path - os.environ["VIRTUAL_ENV"] = self.virtualenv_location - from .vendor.pip_shims.shims import get_installed_distributions - - return get_installed_distributions(local_only=True) + packages = [ + pkg for pkg in workingset + if _normalized(self.locate_dist(pkg)).startswith(prefix) + ] + return packages else: - return [] + return [pkg for pkg in packages] @classmethod def _sanitize(cls, name): @@ -902,3 +921,34 @@ def proper_case_section(self, section): del section[dep] # Return whether or not values have been changed. return changed_values + + @property + def _pyversion(self): + include_dir = vistir.compat.Path(self.virtualenv_location) / "include" + python_path = next(iter(list(include_dir.iterdir())), None) + if python_path and python_path.name.startswith("python"): + python_version = python_path.name.replace("python", "") + py_version_short, abiflags = python_version[:3], python_version[3:] + return {"py_version_short": py_version_short, "abiflags": abiflags} + return {} + + @property + def env_paths(self): + import sysconfig + location = self.virtualenv_location if self.virtualenv_location else sys.prefix + prefix = vistir.compat.Path(location).as_posix() + scheme = sysconfig._get_default_scheme() + config = { + "base": prefix, + "installed_base": prefix, + "platbase": prefix, + "installed_platbase": prefix + } + config.update(self._pyversion) + paths = { + k: v.format(**config) + for k, v in sysconfig._INSTALL_SCHEMES[scheme].items() + } + if "prefix" not in paths: + paths["prefix"] = prefix + return paths