Skip to content

Commit

Permalink
Merge pull request #2976 from pypa/fix-pipenv-clean
Browse files Browse the repository at this point in the history
Properly scope pipenv clean to local env
  • Loading branch information
techalchemy committed Oct 10, 2018
2 parents d3da491 + b408fd3 commit 51b02bd
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 24 deletions.
1 change: 1 addition & 0 deletions news/2849.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a bug in ``pipenv clean`` which caused global packages to sometimes be inadvertently targeted for cleanup.
4 changes: 1 addition & 3 deletions pipenv/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down
87 changes: 70 additions & 17 deletions pipenv/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -279,26 +280,47 @@ 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 dist_is_in_project(self, dist):
prefix = _normalized(self.env_paths["prefix"])
location = self.locate_dist(dist)
if not location:
return False
return _normalized(location).startswith(prefix)

def get_installed_packages(self):
workingset = self.working_set
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 self.dist_is_in_project(pkg)]
else:
return []
packages = [pkg for pkg in packages]
return packages

@classmethod
def _sanitize(cls, name):
Expand Down Expand Up @@ -903,3 +925,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
16 changes: 12 additions & 4 deletions tests/integration/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,13 @@ def test_pipenv_clean_pip_no_warnings(PipenvInstance):
with PipenvInstance(chdir=True) as p:
with open('setup.py', 'w') as f:
f.write('from setuptools import setup; setup(name="empty")')
p.pipenv('run pip install -e .')
assert p.pipenv('clean').out
c = p.pipenv('install -e .')
assert c.return_code == 0
c = p.pipenv('run pip install pytz')
assert c.return_code == 0
c = p.pipenv('clean')
assert c.return_code == 0
assert c.out, "{0} -- STDERR: {1}".format(c.out, c.err)


@pytest.mark.cli
Expand All @@ -114,8 +119,11 @@ def test_pipenv_clean_pip_warnings(PipenvInstance):
f.write('from setuptools import setup; setup(name="empty")')
# create a fake git repo to trigger a pip freeze warning
os.mkdir('.git')
p.pipenv('run pip install -e .')
assert p.pipenv('clean').out
c = p.pipenv("run pip install -e .")
assert c.return_code == 0
c = p.pipenv('clean')
assert c.return_code == 0
assert c.err


@pytest.mark.cli
Expand Down

0 comments on commit 51b02bd

Please sign in to comment.