diff --git a/pip/req/req_set.py b/pip/req/req_set.py index a4e6b0e161b..820837ae0a2 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -718,6 +718,7 @@ def install(self, install_options, global_options=(), *args, **kwargs): the packages) """ to_install = self._to_install() + editable_reinstall = False if to_install: logger.info( @@ -734,6 +735,23 @@ def install(self, install_options, global_options=(), *args, **kwargs): ) with indent_log(): requirement.uninstall(auto_confirm=True) + + if requirement.installed_version and requirement.editable: + # If we have an existing installation but are + # re-installing as editable, make sure we remove + # the existing version. Note that with + # setuptools<25 this is not strictly required, as + # there setuptools will modify easy-install.pth to + # put the "develop" mode install first in sys.path + # (see SETUPTOOLS_SYS_PATH_TECHNIQUE), effectively + # overwriting the prior installed version. + logger.info( + 'Found prior install %s, reinstalling for develop mode' + % requirement.installed_version) + with indent_log(): + requirement.uninstall(auto_confirm=True) + editable_reinstall = True + try: requirement.install( install_options, @@ -743,12 +761,12 @@ def install(self, install_options, global_options=(), *args, **kwargs): ) except: # if install did not succeed, rollback previous uninstall - if (requirement.conflicts_with and not - requirement.install_succeeded): + if ((requirement.conflicts_with or editable_reinstall) and + not requirement.install_succeeded): requirement.rollback_uninstall() raise else: - if (requirement.conflicts_with and + if ((requirement.conflicts_with or editable_reinstall) and requirement.install_succeeded): requirement.commit_uninstall() requirement.remove_temporary_source() diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index 1440f3335f9..967487f4596 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -12,7 +12,7 @@ from tests.lib import (pyversion, pyversion_tuple, _create_test_package, _create_svn_repo, path_to_url, requirements_file) -from tests.lib.local_repos import local_checkout +from tests.lib.local_repos import local_checkout, local_repo from tests.lib.path import Path @@ -1026,3 +1026,25 @@ def test_double_install_fail(script, data): msg = ("Double requirement given: pip==7.1.2 (already in pip==*, " "name='pip')") assert msg in result.stderr + + +@pytest.mark.network +def test_update_to_develop(script, tmpdir): + """ + Test updating from install to develop mode removes original package + """ + path = local_repo( + 'git+http://github.com/pypa/pip-test-package.git', + tmpdir.join("cache"), + ) + + # regular install, then re-install with develop mode + result = script.pip( + 'install', '%s' % path, expect_error=False) + result = script.pip( + 'install', '-e', '%s' % path, expect_error=False) + + # make sure we have overwritten the non-develop install with the + # git version. + result = script.pip('freeze', expect_stderr=True) + assert 'pip-test-package.git' in result.stdout