Do sequential installs on editable dependencies

- Fixes #1111
- Uses existing infrastructure to add editable dependencies to the list
of sequentially installed packages
- Only alters functions used for this purpose
- Essentially there is a race condition because multiple editors are
trying to write to lib/site-packages/easy-install.pth for local editable
packages, so they overwrite one another
This commit is contained in:
Dan Ryan
2017-11-22 21:55:49 -05:00
parent 704c622369
commit 3ac8b89a83
3 changed files with 25 additions and 24 deletions
+12 -14
View File
@@ -33,7 +33,7 @@ from click_didyoumean import DYMCommandCollection
from .project import Project
from .utils import (
convert_deps_from_pip, convert_deps_to_pip, is_required_version,
proper_case, pep423_name, split_vcs, resolve_deps, shellquote, is_vcs,
proper_case, pep423_name, split_vcs_editable, resolve_deps, shellquote, is_vcs,
python_version, suggest_package, find_windows_executable, is_file,
prepare_pip_source_args, temp_environ, is_valid_url, download_file,
get_requirement, need_update_check, touch_update_stamp
@@ -765,10 +765,10 @@ def do_install_dependencies(
if skip_lock or only or not project.lockfile_exists:
if not bare:
click.echo(crayons.normal(u'Installing dependencies from Pipfile…', bold=True))
lockfile = split_vcs(project._lockfile)
lockfile = split_vcs_editable(project._lockfile)
else:
with open(project.lockfile_location) as f:
lockfile = split_vcs(simplejson.load(f))
lockfile = split_vcs_editable(simplejson.load(f))
if not bare:
click.echo(
@@ -784,26 +784,25 @@ def do_install_dependencies(
no_deps = (not skip_lock)
deps = {}
vcs_deps = {}
vcs_editable_deps = {}
# Store dev only deps for a requirements output
dev_deps = {}
dev_vcs_deps = {}
dev_vcs_editable = {}
# Add development deps if --dev was passed.
if dev:
deps.update(lockfile['develop'])
vcs_deps.update(lockfile.get('develop-vcs', {}))
vcs_editable_deps.update(lockfile.get('develop-editable', {}))
# Add only dev deps if requirements was passed
if requirements:
dev_deps.update(lockfile['develop'])
dev_vcs_deps.update(lockfile.get('develop-vcs', {}))
dev_vcs_editable.update(lockfile.get('develop-editable', {}))
# Install default dependencies, always.
deps.update(lockfile['default'] if not only else {})
vcs_deps.update(lockfile.get('default-vcs', {}))
vcs_editable_deps.update(lockfile.get('default-editable', {}))
if ignore_hashes:
# Remove hashes from generated requirements.
@@ -815,8 +814,8 @@ def do_install_dependencies(
deps_list = [(d, ignore_hashes, blocking) for d in convert_deps_to_pip(deps, project, r=False, include_index=True)]
failed_deps_list = []
if len(vcs_deps):
deps_list.extend((d, True, True) for d in convert_deps_to_pip(vcs_deps, project, r=False))
if len(vcs_editable_deps):
deps_list.extend((d, True, True) for d in convert_deps_to_pip(vcs_editable_deps, project, r=False))
# --requirements was passed.
if requirements:
@@ -828,13 +827,12 @@ def do_install_dependencies(
# Output only dev dependencies
if dev:
dev_deps_list = [(d, ignore_hashes, blocking) for d in convert_deps_to_pip(dev_deps, project, r=False, include_index=True)]
if len(dev_vcs_deps):
dev_deps_list.extend((d, True, True) for d in convert_deps_to_pip(dev_vcs_deps, project, r=False))
if len(dev_vcs_editable):
dev_deps_list.extend((d, True, True) for d in convert_deps_to_pip(dev_vcs_editable, project, r=False))
click.echo('\n'.join(d[0] for d in dev_deps_list))
sys.exit(0)
procs = []
deps_list_bar = progress.bar(deps_list, label=INSTALL_LABEL if os.name != 'nt' else '')
+8 -5
View File
@@ -919,19 +919,22 @@ def proper_case(package_name):
return good_name
def split_vcs(split_file):
"""Split VCS dependencies out from file."""
def split_vcs_editable(split_file):
"""Split VCS and editable dependencies out from file."""
if 'packages' in split_file or 'dev-packages' in split_file:
sections = ('packages', 'dev-packages')
elif 'default' in split_file or 'develop' in split_file:
sections = ('default', 'develop')
# For each vcs entry in a given section, move it to section-vcs.
# For each vcs or editable entry in a given section, move it to section-editable.
for section in sections:
entries = split_file.get(section, {})
vcs_dict = dict((k, entries.pop(k)) for k in list(entries.keys()) if is_vcs(entries[k]))
split_file[section + '-vcs'] = vcs_dict
editable_dict = {}
for k in list(entries.keys()):
if is_vcs(entries[k]) or (hasattr(entries[k], 'keys') and entries[k].get('editable') is True):
editable_dict[k] = entries.pop(k)
split_file[section + '-editable'] = editable_dict
return split_file
+5 -5
View File
@@ -131,7 +131,7 @@ class TestUtils:
def test_is_vcs(self, entry, expected):
assert pipenv.utils.is_vcs(entry) is expected
def test_split_vcs(self):
def test_split_editable_vcs(self):
pipfile_dict = {
'packages': {
'requests': {'git': 'https://github.com/kennethreitz/requests.git'},
@@ -143,13 +143,13 @@ class TestUtils:
'crayons': {'hg': 'https://hg.alsonotreal.com/crayons'}
}
}
split_dict = pipenv.utils.split_vcs(pipfile_dict)
split_dict = pipenv.utils.split_vcs_editable(pipfile_dict)
assert list(split_dict['packages'].keys()) == ['Flask']
assert split_dict['packages-vcs'] == {'requests': {'git': 'https://github.com/kennethreitz/requests.git'}}
assert split_dict['packages-editable'] == {'requests': {'git': 'https://github.com/kennethreitz/requests.git'}}
assert list(split_dict['dev-packages'].keys()) == ['Django']
assert 'click' in split_dict['dev-packages-vcs']
assert 'crayons' in split_dict['dev-packages-vcs']
assert 'click' in split_dict['dev-packages-editable']
assert 'crayons' in split_dict['dev-packages-editable']
def test_python_version_from_bad_path(self):
assert pipenv.utils.python_version("/fake/path") is None