Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly scope pipenv clean to local env #2976

Merged
merged 6 commits into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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