Skip to content

Commit 402240c

Browse files
authored
Merge pull request #1830 from benoit-pierre/pip_wheels
drop easy_install script/command, re-implement `fetch_build_egg` to use pip
2 parents a007982 + b8101f0 commit 402240c

File tree

15 files changed

+364
-1258
lines changed

15 files changed

+364
-1258
lines changed

docs/easy_install.txt

Lines changed: 0 additions & 1085 deletions
This file was deleted.

docs/index.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,4 @@ Documentation content:
2121
python3
2222
development
2323
roadmap
24-
Deprecated: Easy Install <easy_install>
2524
history

docs/setuptools.txt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,11 @@ unless you need the associated ``setuptools`` feature.
282282
``setup_requires``
283283
A string or list of strings specifying what other distributions need to
284284
be present in order for the *setup script* to run. ``setuptools`` will
285-
attempt to obtain these before processing the rest of the setup script or
286-
commands. This argument is needed if you are using distutils extensions as
287-
part of your build process; for example, extensions that process setup()
288-
arguments and turn them into EGG-INFO metadata files.
285+
attempt to obtain these (using pip if available) before processing the
286+
rest of the setup script or commands. This argument is needed if you
287+
are using distutils extensions as part of your build process; for
288+
example, extensions that process setup() arguments and turn them into
289+
EGG-INFO metadata files.
289290

290291
(Note: projects listed in ``setup_requires`` will NOT be automatically
291292
installed on the system where the setup script is being run. They are
@@ -332,10 +333,10 @@ unless you need the associated ``setuptools`` feature.
332333
needed to install it, you can use this option to specify them. It should
333334
be a string or list of strings specifying what other distributions need to
334335
be present for the package's tests to run. When you run the ``test``
335-
command, ``setuptools`` will attempt to obtain these. Note that these
336-
required projects will *not* be installed on the system where the tests
337-
are run, but only downloaded to the project's setup directory if they're
338-
not already installed locally.
336+
command, ``setuptools`` will attempt to obtain these (using pip if
337+
available). Note that these required projects will *not* be installed on
338+
the system where the tests are run, but only downloaded to the project's setup
339+
directory if they're not already installed locally.
339340

340341
New in 41.5.0: Deprecated the test command.
341342

easy_install.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ classifiers =
5151
[options]
5252
zip_safe = True
5353
python_requires = >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
54-
py_modules = easy_install
5554
packages = find:
5655

5756
[options.packages.find]

setup.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,6 @@ def read_commands():
3131
return command_ns['__all__']
3232

3333

34-
def _gen_console_scripts():
35-
yield "easy_install = setuptools.command.easy_install:main"
36-
37-
# Gentoo distributions manage the python-version-specific scripts
38-
# themselves, so those platforms define an environment variable to
39-
# suppress the creation of the version-specific scripts.
40-
var_names = (
41-
'SETUPTOOLS_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT',
42-
'DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT',
43-
)
44-
if any(os.environ.get(var) not in (None, "", "0") for var in var_names):
45-
return
46-
tmpl = "easy_install-{shortver} = setuptools.command.easy_install:main"
47-
yield tmpl.format(shortver='{}.{}'.format(*sys.version_info))
48-
49-
5034
package_data = dict(
5135
setuptools=['script (dev).tmpl', 'script.tmpl', 'site-patch.py'],
5236
)
@@ -125,9 +109,6 @@ def pypi_link(pkg_filename):
125109
"depends.txt = setuptools.command.egg_info:warn_depends_obsolete",
126110
"dependency_links.txt = setuptools.command.egg_info:overwrite_arg",
127111
],
128-
"console_scripts": list(_gen_console_scripts()),
129-
"setuptools.installation":
130-
['eggsecutable = setuptools.command.easy_install:bootstrap'],
131112
},
132113
dependency_links=[
133114
pypi_link(

setuptools/command/easy_install.py

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373

7474
__all__ = [
7575
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
76-
'main', 'get_exe_prefixes',
76+
'get_exe_prefixes',
7777
]
7878

7979

@@ -410,7 +410,13 @@ def expand_dirs(self):
410410
]
411411
self._expand_attrs(dirs)
412412

413-
def run(self):
413+
def run(self, show_deprecation=True):
414+
if show_deprecation:
415+
self.announce(
416+
"WARNING: The easy_install command is deprecated "
417+
"and will be removed in a future version."
418+
, log.WARN,
419+
)
414420
if self.verbose != self.distribution.verbose:
415421
log.set_verbosity(self.verbose)
416422
try:
@@ -2283,59 +2289,6 @@ def current_umask():
22832289
return tmp
22842290

22852291

2286-
def bootstrap():
2287-
# This function is called when setuptools*.egg is run using /bin/sh
2288-
import setuptools
2289-
2290-
argv0 = os.path.dirname(setuptools.__path__[0])
2291-
sys.argv[0] = argv0
2292-
sys.argv.append(argv0)
2293-
main()
2294-
2295-
2296-
def main(argv=None, **kw):
2297-
from setuptools import setup
2298-
from setuptools.dist import Distribution
2299-
2300-
class DistributionWithoutHelpCommands(Distribution):
2301-
common_usage = ""
2302-
2303-
def _show_help(self, *args, **kw):
2304-
with _patch_usage():
2305-
Distribution._show_help(self, *args, **kw)
2306-
2307-
if argv is None:
2308-
argv = sys.argv[1:]
2309-
2310-
with _patch_usage():
2311-
setup(
2312-
script_args=['-q', 'easy_install', '-v'] + argv,
2313-
script_name=sys.argv[0] or 'easy_install',
2314-
distclass=DistributionWithoutHelpCommands,
2315-
**kw
2316-
)
2317-
2318-
2319-
@contextlib.contextmanager
2320-
def _patch_usage():
2321-
import distutils.core
2322-
USAGE = textwrap.dedent("""
2323-
usage: %(script)s [options] requirement_or_url ...
2324-
or: %(script)s --help
2325-
""").lstrip()
2326-
2327-
def gen_usage(script_name):
2328-
return USAGE % dict(
2329-
script=os.path.basename(script_name),
2330-
)
2331-
2332-
saved = distutils.core.gen_usage
2333-
distutils.core.gen_usage = gen_usage
2334-
try:
2335-
yield
2336-
finally:
2337-
distutils.core.gen_usage = saved
2338-
23392292
class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
23402293
"""Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning."""
23412294

setuptools/command/install.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def do_egg_install(self):
114114
args.insert(0, setuptools.bootstrap_install_from)
115115

116116
cmd.args = args
117-
cmd.run()
117+
cmd.run(show_deprecation=False)
118118
setuptools.bootstrap_install_from = None
119119

120120

setuptools/dist.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -759,32 +759,8 @@ def get_egg_cache_dir(self):
759759

760760
def fetch_build_egg(self, req):
761761
"""Fetch an egg needed for building"""
762-
from setuptools.command.easy_install import easy_install
763-
dist = self.__class__({'script_args': ['easy_install']})
764-
opts = dist.get_option_dict('easy_install')
765-
opts.clear()
766-
opts.update(
767-
(k, v)
768-
for k, v in self.get_option_dict('easy_install').items()
769-
if k in (
770-
# don't use any other settings
771-
'find_links', 'site_dirs', 'index_url',
772-
'optimize', 'site_dirs', 'allow_hosts',
773-
))
774-
if self.dependency_links:
775-
links = self.dependency_links[:]
776-
if 'find_links' in opts:
777-
links = opts['find_links'][1] + links
778-
opts['find_links'] = ('setup', links)
779-
install_dir = self.get_egg_cache_dir()
780-
cmd = easy_install(
781-
dist, args=["x"], install_dir=install_dir,
782-
exclude_scripts=True,
783-
always_copy=False, build_directory=None, editable=False,
784-
upgrade=False, multi_version=True, no_report=True, user=False
785-
)
786-
cmd.ensure_finalized()
787-
return cmd.easy_install(req)
762+
from setuptools.installer import fetch_build_egg
763+
return fetch_build_egg(self, req)
788764

789765
def _set_global_opts_from_features(self):
790766
"""Add --with-X/--without-X options based on optional features"""

setuptools/installer.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import glob
2+
import os
3+
import subprocess
4+
import sys
5+
from distutils import log
6+
from distutils.errors import DistutilsError
7+
8+
import pkg_resources
9+
from setuptools.command.easy_install import easy_install
10+
from setuptools.wheel import Wheel
11+
12+
from .py31compat import TemporaryDirectory
13+
14+
15+
def _legacy_fetch_build_egg(dist, req):
16+
"""Fetch an egg needed for building.
17+
18+
Legacy path using EasyInstall.
19+
"""
20+
tmp_dist = dist.__class__({'script_args': ['easy_install']})
21+
opts = tmp_dist.get_option_dict('easy_install')
22+
opts.clear()
23+
opts.update(
24+
(k, v)
25+
for k, v in dist.get_option_dict('easy_install').items()
26+
if k in (
27+
# don't use any other settings
28+
'find_links', 'site_dirs', 'index_url',
29+
'optimize', 'site_dirs', 'allow_hosts',
30+
))
31+
if dist.dependency_links:
32+
links = dist.dependency_links[:]
33+
if 'find_links' in opts:
34+
links = opts['find_links'][1] + links
35+
opts['find_links'] = ('setup', links)
36+
install_dir = dist.get_egg_cache_dir()
37+
cmd = easy_install(
38+
tmp_dist, args=["x"], install_dir=install_dir,
39+
exclude_scripts=True,
40+
always_copy=False, build_directory=None, editable=False,
41+
upgrade=False, multi_version=True, no_report=True, user=False
42+
)
43+
cmd.ensure_finalized()
44+
return cmd.easy_install(req)
45+
46+
47+
def fetch_build_egg(dist, req):
48+
"""Fetch an egg needed for building.
49+
50+
Use pip/wheel to fetch/build a wheel."""
51+
# Check pip is available.
52+
try:
53+
pkg_resources.get_distribution('pip')
54+
except pkg_resources.DistributionNotFound:
55+
dist.announce(
56+
'WARNING: The pip package is not available, falling back '
57+
'to EasyInstall for handling setup_requires/test_requires; '
58+
'this is deprecated and will be removed in a future version.'
59+
, log.WARN
60+
)
61+
return _legacy_fetch_build_egg(dist, req)
62+
# Warn if wheel is not.
63+
try:
64+
pkg_resources.get_distribution('wheel')
65+
except pkg_resources.DistributionNotFound:
66+
dist.announce('WARNING: The wheel package is not available.', log.WARN)
67+
if not isinstance(req, pkg_resources.Requirement):
68+
req = pkg_resources.Requirement.parse(req)
69+
# Take easy_install options into account, but do not override relevant
70+
# pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll
71+
# take precedence.
72+
opts = dist.get_option_dict('easy_install')
73+
if 'allow_hosts' in opts:
74+
raise DistutilsError('the `allow-hosts` option is not supported '
75+
'when using pip to install requirements.')
76+
if 'PIP_QUIET' in os.environ or 'PIP_VERBOSE' in os.environ:
77+
quiet = False
78+
else:
79+
quiet = True
80+
if 'PIP_INDEX_URL' in os.environ:
81+
index_url = None
82+
elif 'index_url' in opts:
83+
index_url = opts['index_url'][1]
84+
else:
85+
index_url = None
86+
if 'find_links' in opts:
87+
find_links = opts['find_links'][1][:]
88+
else:
89+
find_links = []
90+
if dist.dependency_links:
91+
find_links.extend(dist.dependency_links)
92+
eggs_dir = os.path.realpath(dist.get_egg_cache_dir())
93+
environment = pkg_resources.Environment()
94+
for egg_dist in pkg_resources.find_distributions(eggs_dir):
95+
if egg_dist in req and environment.can_add(egg_dist):
96+
return egg_dist
97+
with TemporaryDirectory() as tmpdir:
98+
cmd = [
99+
sys.executable, '-m', 'pip',
100+
'--disable-pip-version-check',
101+
'wheel', '--no-deps',
102+
'-w', tmpdir,
103+
]
104+
if quiet:
105+
cmd.append('--quiet')
106+
if index_url is not None:
107+
cmd.extend(('--index-url', index_url))
108+
if find_links is not None:
109+
for link in find_links:
110+
cmd.extend(('--find-links', link))
111+
# If requirement is a PEP 508 direct URL, directly pass
112+
# the URL to pip, as `req @ url` does not work on the
113+
# command line.
114+
if req.url:
115+
cmd.append(req.url)
116+
else:
117+
cmd.append(str(req))
118+
try:
119+
subprocess.check_call(cmd)
120+
except subprocess.CalledProcessError as e:
121+
raise DistutilsError(str(e))
122+
wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0])
123+
dist_location = os.path.join(eggs_dir, wheel.egg_name())
124+
wheel.install_as_egg(dist_location)
125+
dist_metadata = pkg_resources.PathMetadata(
126+
dist_location, os.path.join(dist_location, 'EGG-INFO'))
127+
dist = pkg_resources.Distribution.from_filename(
128+
dist_location, metadata=dist_metadata)
129+
return dist

0 commit comments

Comments
 (0)