Skip to content

Commit bfe99a9

Browse files
committed
Merge pull request #992 from qwcode/upgrade_distribute
Solution for upgrading to the new setuptools
2 parents e0e19cc + fd99bd3 commit bfe99a9

File tree

6 files changed

+80
-91
lines changed

6 files changed

+80
-91
lines changed

pip/backwardcompat/__init__.py

-8
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,6 @@ def fwrite(f, s):
6161
def get_http_message_param(http_message, param, default_value):
6262
return http_message.get_param(param, default_value)
6363

64-
install_skip_reqs = {
65-
'distribute' : 'Can not install distribute due to bootstrap issues'
66-
}
67-
wheel_skip_reqs = {
68-
'distribute' : 'Can not build wheels for distribute due to bootstrap issues'
69-
}
7064
bytes = bytes
7165
string_types = (str,)
7266
raw_input = input
@@ -99,8 +93,6 @@ def get_http_message_param(http_message, param, default_value):
9993
result = http_message.getparam(param)
10094
return result or default_value
10195

102-
install_skip_reqs = {}
103-
wheel_skip_reqs = {}
10496
bytes = str
10597
string_types = (basestring,)
10698
reduce = reduce

pip/commands/install.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from pip.req import InstallRequirement, RequirementSet, parse_requirements
66
from pip.log import logger
77
from pip.locations import src_prefix, virtualenv_no_global, distutils_scheme
8-
from pip.backwardcompat import install_skip_reqs
98
from pip.basecommand import Command
109
from pip.index import PackageFinder
1110
from pip.exceptions import InstallationError, CommandError
@@ -209,8 +208,7 @@ def run(self, options, args):
209208
ignore_dependencies=options.ignore_dependencies,
210209
force_reinstall=options.force_reinstall,
211210
use_user_site=options.use_user_site,
212-
target_dir=temp_target_dir,
213-
skip_reqs=install_skip_reqs)
211+
target_dir=temp_target_dir)
214212
for name in args:
215213
requirement_set.add_requirement(
216214
InstallRequirement.from_line(name, None, prereleases=options.pre))

pip/commands/wheel.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from pip.basecommand import Command
77
from pip.index import PackageFinder
88
from pip.log import logger
9-
from pip.backwardcompat import wheel_skip_reqs
109
from pip.exceptions import CommandError
1110
from pip.req import InstallRequirement, RequirementSet, parse_requirements
1211
from pip.util import normalize_path
@@ -104,8 +103,7 @@ def run(self, options, args):
104103
download_dir=None,
105104
download_cache=options.download_cache,
106105
ignore_dependencies=options.ignore_dependencies,
107-
ignore_installed=True,
108-
skip_reqs=wheel_skip_reqs)
106+
ignore_installed=True)
109107

110108
#parse args and/or requirements files
111109
for name in args:

pip/req.py

+61-25
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,21 @@ def run_egg_info(self, force_root_egg_info=False):
226226
logger.notify('Running setup.py egg_info for package from %s' % self.url)
227227
logger.indent += 2
228228
try:
229+
230+
# if it's distribute>=0.7, it won't contain an importable
231+
# setuptools, and having an egg-info dir blocks the ability of
232+
# setup.py to find setuptools plugins, so delete the egg-info dir if
233+
# no setuptools. it will get recreated by the run of egg_info
234+
# NOTE: this self.name check only works when installing from a specifier
235+
# (not archive path/urls)
236+
# TODO: take this out later
237+
if self.name == 'distribute' and not os.path.isdir(os.path.join(self.source_dir, 'setuptools')):
238+
rmtree(os.path.join(self.source_dir, 'distribute.egg-info'))
239+
229240
script = self._run_setup_py
230241
script = script.replace('__SETUP_PY__', repr(self.setup_py))
231242
script = script.replace('__PKG_NAME__', repr(self.name))
243+
egg_info_cmd = [sys.executable, '-c', script, 'egg_info']
232244
# We can't put the .egg-info files at the root, because then the source code will be mistaken
233245
# for an installed egg, causing problems
234246
if self.editable or force_root_egg_info:
@@ -239,7 +251,7 @@ def run_egg_info(self, force_root_egg_info=False):
239251
os.makedirs(egg_info_dir)
240252
egg_base_option = ['--egg-base', 'pip-egg-info']
241253
call_subprocess(
242-
[sys.executable, '-c', script, 'egg_info'] + egg_base_option,
254+
egg_info_cmd + egg_base_option,
243255
cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False,
244256
command_level=logger.VERBOSE_DEBUG,
245257
command_desc='python setup.py egg_info')
@@ -584,13 +596,12 @@ def install(self, install_options, global_options=(), root=None):
584596
temp_location = tempfile.mkdtemp('-record', 'pip-')
585597
record_filename = os.path.join(temp_location, 'install-record.txt')
586598
try:
587-
install_args = [
588-
sys.executable, '-c',
589-
"import setuptools;__file__=%r;"\
590-
"exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))" % self.setup_py] +\
591-
list(global_options) + [
592-
'install',
593-
'--record', record_filename]
599+
install_args = [sys.executable]
600+
install_args.append('-c')
601+
install_args.append(
602+
"import setuptools;__file__=%r;"\
603+
"exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))" % self.setup_py)
604+
install_args += list(global_options) + ['install','--record', record_filename]
594605

595606
if not self.as_egg:
596607
install_args += ['--single-version-externally-managed']
@@ -702,7 +713,15 @@ def check_if_exists(self):
702713
if self.req is None:
703714
return False
704715
try:
705-
self.satisfied_by = pkg_resources.get_distribution(self.req)
716+
# if we've already set distribute as a conflict to setuptools
717+
# then this check has already run before. we don't want it to
718+
# run again, and return False, since it would block the uninstall
719+
if (self.req.project_name == 'setuptools'
720+
and self.conflicts_with
721+
and self.conflicts_with.project_name == 'distribute'):
722+
return True
723+
else:
724+
self.satisfied_by = pkg_resources.get_distribution(self.req)
706725
except pkg_resources.DistributionNotFound:
707726
return False
708727
except pkg_resources.VersionConflict:
@@ -830,8 +849,7 @@ class RequirementSet(object):
830849

831850
def __init__(self, build_dir, src_dir, download_dir, download_cache=None,
832851
upgrade=False, ignore_installed=False, as_egg=False, target_dir=None,
833-
ignore_dependencies=False, force_reinstall=False, use_user_site=False,
834-
skip_reqs={}):
852+
ignore_dependencies=False, force_reinstall=False, use_user_site=False):
835853
self.build_dir = build_dir
836854
self.src_dir = src_dir
837855
self.download_dir = download_dir
@@ -849,10 +867,7 @@ def __init__(self, build_dir, src_dir, download_dir, download_cache=None,
849867
self.reqs_to_cleanup = []
850868
self.as_egg = as_egg
851869
self.use_user_site = use_user_site
852-
# Set from --target option
853-
self.target_dir = target_dir
854-
# Requirements (by project name) to be skipped
855-
self.skip_reqs = skip_reqs
870+
self.target_dir = target_dir #set from --target option
856871

857872
def __str__(self):
858873
reqs = [req for req in self.requirements.values()
@@ -862,9 +877,6 @@ def __str__(self):
862877

863878
def add_requirement(self, install_req):
864879
name = install_req.name
865-
if name and name.lower() in self.skip_reqs:
866-
logger.notify("Skipping %s: %s" %( name, self.skip_reqs[name.lower()]))
867-
return False
868880
install_req.as_egg = self.as_egg
869881
install_req.use_user_site = self.use_user_site
870882
install_req.target_dir = self.target_dir
@@ -880,7 +892,6 @@ def add_requirement(self, install_req):
880892
## FIXME: what about other normalizations? E.g., _ vs. -?
881893
if name.lower() != name:
882894
self.requirement_aliases[name.lower()] = name
883-
return True
884895

885896
def has_requirement(self, project_name):
886897
for name in project_name, project_name.lower():
@@ -1086,8 +1097,8 @@ def prepare_files(self, finder, force_root_egg_info=False, bundle=False):
10861097
if is_bundle:
10871098
req_to_install.move_bundle_files(self.build_dir, self.src_dir)
10881099
for subreq in req_to_install.bundle_requirements():
1089-
if self.add_requirement(subreq):
1090-
reqs.append(subreq)
1100+
reqs.append(subreq)
1101+
self.add_requirement(subreq)
10911102
elif is_wheel:
10921103
req_to_install.source_dir = location
10931104
req_to_install.url = url.url
@@ -1101,8 +1112,8 @@ def prepare_files(self, finder, force_root_egg_info=False, bundle=False):
11011112
continue
11021113
subreq = InstallRequirement(str(subreq),
11031114
req_to_install)
1104-
if self.add_requirement(subreq):
1105-
reqs.append(subreq)
1115+
reqs.append(subreq)
1116+
self.add_requirement(subreq)
11061117
elif self.is_download:
11071118
req_to_install.source_dir = location
11081119
req_to_install.run_egg_info()
@@ -1149,8 +1160,8 @@ def prepare_files(self, finder, force_root_egg_info=False, bundle=False):
11491160
## FIXME: check for conflict
11501161
continue
11511162
subreq = InstallRequirement(req, req_to_install)
1152-
if self.add_requirement(subreq):
1153-
reqs.append(subreq)
1163+
reqs.append(subreq)
1164+
self.add_requirement(subreq)
11541165
if not self.has_requirement(req_to_install.name):
11551166
#'unnamed' requirements will get added here
11561167
self.add_requirement(req_to_install)
@@ -1224,11 +1235,36 @@ def install(self, install_options, global_options=(), *args, **kwargs):
12241235
to_install = [r for r in self.requirements.values()
12251236
if not r.satisfied_by]
12261237

1238+
# move distribute>=0.7 to the end because it does not contain an
1239+
# importable setuptools. by moving it to the end, we ensure it's
1240+
# setuptools dependency is handled first, which will provide an
1241+
# importable setuptools package
1242+
# TODO: take this out later
1243+
distribute_req = pkg_resources.Requirement.parse("distribute>=0.7")
1244+
for req in to_install:
1245+
if req.name == 'distribute' and req.installed_version in distribute_req:
1246+
to_install.remove(req)
1247+
to_install.append(req)
1248+
12271249
if to_install:
12281250
logger.notify('Installing collected packages: %s' % ', '.join([req.name for req in to_install]))
12291251
logger.indent += 2
12301252
try:
12311253
for requirement in to_install:
1254+
1255+
# when installing setuptools>=0.7.2 in py2, we need to force setuptools
1256+
# to uninstall distribute. In py3, which is always using distribute, this
1257+
# conversion is already happening in distribute's pkg_resources.
1258+
# TODO: remove this later
1259+
setuptools_req = pkg_resources.Requirement.parse("setuptools>=0.7.2")
1260+
if requirement.name == 'setuptools' and requirement.installed_version in setuptools_req:
1261+
try:
1262+
existing_distribute = pkg_resources.get_distribution("distribute")
1263+
requirement.conflicts_with = existing_distribute
1264+
except:
1265+
# distribute wasn't installed
1266+
pass
1267+
12321268
if requirement.conflicts_with:
12331269
logger.notify('Found existing installation: %s'
12341270
% requirement.conflicts_with)

tests/functional/test_install.py

+15-29
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@
1010
from tests.lib.path import Path
1111

1212

13+
def test_pip_second_command_line_interface_works():
14+
"""
15+
Check if ``pip-<PYVERSION>`` commands behaves equally
16+
"""
17+
e = reset_env()
18+
19+
args = ['pip-%s' % pyversion]
20+
args.extend(['install', 'INITools==0.2'])
21+
result = e.run(*args)
22+
egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion
23+
initools_folder = e.site_packages / 'initools'
24+
assert egg_info_folder in result.files_created, str(result)
25+
assert initools_folder in result.files_created, str(result)
26+
27+
1328
def test_install_from_pypi():
1429
"""
1530
Test installing a package from PyPI.
@@ -242,7 +257,6 @@ def test_install_as_egg():
242257
assert join(egg_folder, 'fspkg') in result.files_created, str(result)
243258

244259

245-
246260
def test_install_curdir():
247261
"""
248262
Test installing current directory ('.').
@@ -467,31 +481,3 @@ def test_url_req_case_mismatch():
467481
egg_folder = env.site_packages / 'Upper-2.0-py%s.egg-info' % pyversion
468482
assert egg_folder not in result.files_created, str(result)
469483

470-
471-
def test_dont_install_distribute_in_py3():
472-
"""
473-
Test we skip distribute in py3
474-
"""
475-
if sys.version_info < (3, 0):
476-
raise SkipTest()
477-
env = reset_env()
478-
result = run_pip('install', 'distribute')
479-
assert "Skipping distribute: Can not install distribute due to bootstrap issues" in result.stdout
480-
assert not result.files_updated
481-
482-
483-
def test_pip_second_command_line_interface_works():
484-
"""
485-
Check if ``pip-<PYVERSION>`` commands behaves equally
486-
"""
487-
e = reset_env()
488-
489-
args = ['pip-%s' % pyversion]
490-
args.extend(['install', 'INITools==0.2'])
491-
result = e.run(*args)
492-
egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion
493-
initools_folder = e.site_packages / 'initools'
494-
assert egg_info_folder in result.files_created, str(result)
495-
assert initools_folder in result.files_created, str(result)
496-
497-

tests/unit/test_req.py

+2-23
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,12 @@ def teardown(self):
2323
logger.consumers = []
2424
shutil.rmtree(self.tempdir, ignore_errors=True)
2525

26-
def basic_reqset(self, skip_reqs={}):
26+
def basic_reqset(self):
2727
return RequirementSet(
2828
build_dir=os.path.join(self.tempdir, 'build'),
2929
src_dir=os.path.join(self.tempdir, 'src'),
3030
download_dir=None,
31-
download_cache=os.path.join(self.tempdir, 'download_cache'),
32-
skip_reqs=skip_reqs
31+
download_cache=os.path.join(self.tempdir, 'download_cache')
3332
)
3433

3534
def test_no_reuse_existing_build_dir(self):
@@ -49,26 +48,6 @@ def test_no_reuse_existing_build_dir(self):
4948
finder
5049
)
5150

52-
def test_skip_reqs(self):
53-
"""Test the skip_reqs list works"""
54-
55-
reqset = self.basic_reqset(skip_reqs={'simple':''})
56-
req = InstallRequirement.from_line('simple')
57-
reqset.add_requirement(req)
58-
assert not reqset.has_requirements
59-
finder = PackageFinder([find_links], [])
60-
reqset.prepare_files(finder)
61-
assert not reqset.has_requirements
62-
63-
def test_add_requirement_returns_true_false(self):
64-
"""Test add_requirement returns true of false"""
65-
66-
req = InstallRequirement.from_line('simple')
67-
reqset = self.basic_reqset()
68-
assert True == reqset.add_requirement(req)
69-
reqset = self.basic_reqset(skip_reqs={'simple':''})
70-
assert False == reqset.add_requirement(req)
71-
7251

7352
def test_url_with_query():
7453
"""InstallRequirement should strip the fragment, but not the query."""

0 commit comments

Comments
 (0)