diff --git a/pip/backwardcompat/__init__.py b/pip/backwardcompat/__init__.py index 465759d8027..21d8f10cc13 100644 --- a/pip/backwardcompat/__init__.py +++ b/pip/backwardcompat/__init__.py @@ -61,6 +61,12 @@ def fwrite(f, s): def get_http_message_param(http_message, param, default_value): return http_message.get_param(param, default_value) + install_skip_reqs = { + 'distribute' : 'Can not install distribute due to bootstrap issues' + } + wheel_skip_reqs = { + 'distribute' : 'Can not build wheels for distribute due to bootstrap issues' + } bytes = bytes string_types = (str,) raw_input = input @@ -93,6 +99,8 @@ def get_http_message_param(http_message, param, default_value): result = http_message.getparam(param) return result or default_value + install_skip_reqs = {} + wheel_skip_reqs = {} bytes = str string_types = (basestring,) reduce = reduce diff --git a/pip/commands/install.py b/pip/commands/install.py index 3f53720c885..7f1bc209e22 100644 --- a/pip/commands/install.py +++ b/pip/commands/install.py @@ -5,6 +5,7 @@ from pip.req import InstallRequirement, RequirementSet, parse_requirements from pip.log import logger from pip.locations import src_prefix, virtualenv_no_global, distutils_scheme +from pip.backwardcompat import install_skip_reqs from pip.basecommand import Command from pip.index import PackageFinder from pip.exceptions import InstallationError, CommandError @@ -207,7 +208,8 @@ def run(self, options, args): ignore_dependencies=options.ignore_dependencies, force_reinstall=options.force_reinstall, use_user_site=options.use_user_site, - target_dir=temp_target_dir) + target_dir=temp_target_dir, + skip_reqs=install_skip_reqs) for name in args: requirement_set.add_requirement( InstallRequirement.from_line(name, None, prereleases=options.pre)) diff --git a/pip/commands/wheel.py b/pip/commands/wheel.py index a47b0d1f3e4..7e79522b339 100644 --- a/pip/commands/wheel.py +++ b/pip/commands/wheel.py @@ -6,6 +6,7 @@ from pip.basecommand import Command from pip.index import PackageFinder from pip.log import logger +from pip.backwardcompat import wheel_skip_reqs from pip.exceptions import CommandError from pip.req import InstallRequirement, RequirementSet, parse_requirements from pip.util import normalize_path @@ -107,7 +108,8 @@ def run(self, options, args): download_dir=None, download_cache=options.download_cache, ignore_dependencies=options.ignore_dependencies, - ignore_installed=True) + ignore_installed=True, + skip_reqs=wheel_skip_reqs) #parse args and/or requirements files for name in args: diff --git a/pip/req.py b/pip/req.py index 90809f6bd2b..2f3d23e0092 100644 --- a/pip/req.py +++ b/pip/req.py @@ -842,7 +842,8 @@ class RequirementSet(object): def __init__(self, build_dir, src_dir, download_dir, download_cache=None, upgrade=False, ignore_installed=False, as_egg=False, target_dir=None, - ignore_dependencies=False, force_reinstall=False, use_user_site=False): + ignore_dependencies=False, force_reinstall=False, use_user_site=False, + skip_reqs={}): self.build_dir = build_dir self.src_dir = src_dir self.download_dir = download_dir @@ -860,7 +861,10 @@ def __init__(self, build_dir, src_dir, download_dir, download_cache=None, self.reqs_to_cleanup = [] self.as_egg = as_egg self.use_user_site = use_user_site - self.target_dir = target_dir #set from --target option + # Set from --target option + self.target_dir = target_dir + # Requirements (by project name) to be skipped + self.skip_reqs = skip_reqs def __str__(self): reqs = [req for req in self.requirements.values() @@ -870,6 +874,9 @@ def __str__(self): def add_requirement(self, install_req): name = install_req.name + if name and name.lower() in self.skip_reqs: + logger.notify("Skipping %s: %s" %( name, self.skip_reqs[name.lower()])) + return False install_req.as_egg = self.as_egg install_req.use_user_site = self.use_user_site install_req.target_dir = self.target_dir @@ -885,6 +892,7 @@ def add_requirement(self, install_req): ## FIXME: what about other normalizations? E.g., _ vs. -? if name.lower() != name: self.requirement_aliases[name.lower()] = name + return True def has_requirement(self, project_name): for name in project_name, project_name.lower(): @@ -1090,8 +1098,8 @@ def prepare_files(self, finder, force_root_egg_info=False, bundle=False): if is_bundle: req_to_install.move_bundle_files(self.build_dir, self.src_dir) for subreq in req_to_install.bundle_requirements(): - reqs.append(subreq) - self.add_requirement(subreq) + if self.add_requirement(subreq): + reqs.append(subreq) elif is_wheel: req_to_install.source_dir = location req_to_install.url = url.url @@ -1105,8 +1113,8 @@ def prepare_files(self, finder, force_root_egg_info=False, bundle=False): continue subreq = InstallRequirement(str(subreq), req_to_install) - reqs.append(subreq) - self.add_requirement(subreq) + if self.add_requirement(subreq): + reqs.append(subreq) elif self.is_download: req_to_install.source_dir = location req_to_install.run_egg_info() @@ -1153,8 +1161,8 @@ def prepare_files(self, finder, force_root_egg_info=False, bundle=False): ## FIXME: check for conflict continue subreq = InstallRequirement(req, req_to_install) - reqs.append(subreq) - self.add_requirement(subreq) + if self.add_requirement(subreq): + reqs.append(subreq) if not self.has_requirement(req_to_install.name): #'unnamed' requirements will get added here self.add_requirement(req_to_install) diff --git a/tests/test_basic.py b/tests/test_basic.py index c16fc8ebb24..6d39a352349 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -6,6 +6,7 @@ from os.path import abspath, join, curdir, pardir from nose.tools import assert_raises +from nose import SkipTest from mock import patch from pip.util import rmtree, find_command @@ -348,7 +349,6 @@ def test_install_from_wheel_with_extras(): """ Test installing from a wheel. """ - from nose import SkipTest try: import ast except ImportError: @@ -650,3 +650,14 @@ def test_find_command_trys_supplied_pathext(mock_isfile, getpath_mock): assert mock_isfile.call_args_list == expected, "Actual: %s\nExpected %s" % (mock_isfile.call_args_list, expected) assert not getpath_mock.called, "Should not call get_pathext" + +def test_dont_install_distribute_in_py3(): + """ + Test we skip distribute in py3 + """ + if sys.version_info < (3, 0): + raise SkipTest() + env = reset_env() + result = run_pip('install', 'distribute') + assert "Skipping distribute: Can not install distribute due to bootstrap issues" in result.stdout + assert not result.files_updated diff --git a/tests/test_req.py b/tests/test_req.py index 3d5d333e1d1..f20e1d63180 100644 --- a/tests/test_req.py +++ b/tests/test_req.py @@ -23,12 +23,13 @@ def teardown(self): logger.consumers = [] shutil.rmtree(self.tempdir, ignore_errors=True) - def basic_reqset(self): + def basic_reqset(self, skip_reqs={}): return RequirementSet( build_dir=os.path.join(self.tempdir, 'build'), src_dir=os.path.join(self.tempdir, 'src'), download_dir=None, download_cache=os.path.join(self.tempdir, 'download_cache'), + skip_reqs=skip_reqs ) def test_no_reuse_existing_build_dir(self): @@ -48,3 +49,22 @@ def test_no_reuse_existing_build_dir(self): finder ) + def test_skip_reqs(self): + """Test the skip_reqs list works""" + + reqset = self.basic_reqset(skip_reqs={'simple':''}) + req = InstallRequirement.from_line('simple') + reqset.add_requirement(req) + assert not reqset.has_requirements + finder = PackageFinder([find_links], []) + reqset.prepare_files(finder) + assert not reqset.has_requirements + + def test_add_requirement_returns_true_false(self): + """Test add_requirement returns true of false""" + + req = InstallRequirement.from_line('simple') + reqset = self.basic_reqset() + assert True == reqset.add_requirement(req) + reqset = self.basic_reqset(skip_reqs={'simple':''}) + assert False == reqset.add_requirement(req)