Commit 402240c0 authored by Jason R. Coombs's avatar Jason R. Coombs Committed by GitHub

Merge pull request #1830 from benoit-pierre/pip_wheels

drop easy_install script/command, re-implement `fetch_build_egg` to use pip
parents a0079826 b8101f06
This diff is collapsed.
...@@ -21,5 +21,4 @@ Documentation content: ...@@ -21,5 +21,4 @@ Documentation content:
python3 python3
development development
roadmap roadmap
Deprecated: Easy Install <easy_install>
history history
...@@ -282,10 +282,11 @@ unless you need the associated ``setuptools`` feature. ...@@ -282,10 +282,11 @@ unless you need the associated ``setuptools`` feature.
``setup_requires`` ``setup_requires``
A string or list of strings specifying what other distributions need to A string or list of strings specifying what other distributions need to
be present in order for the *setup script* to run. ``setuptools`` will be present in order for the *setup script* to run. ``setuptools`` will
attempt to obtain these before processing the rest of the setup script or attempt to obtain these (using pip if available) before processing the
commands. This argument is needed if you are using distutils extensions as rest of the setup script or commands. This argument is needed if you
part of your build process; for example, extensions that process setup() are using distutils extensions as part of your build process; for
arguments and turn them into EGG-INFO metadata files. example, extensions that process setup() arguments and turn them into
EGG-INFO metadata files.
(Note: projects listed in ``setup_requires`` will NOT be automatically (Note: projects listed in ``setup_requires`` will NOT be automatically
installed on the system where the setup script is being run. They are installed on the system where the setup script is being run. They are
...@@ -332,10 +333,10 @@ unless you need the associated ``setuptools`` feature. ...@@ -332,10 +333,10 @@ unless you need the associated ``setuptools`` feature.
needed to install it, you can use this option to specify them. It should needed to install it, you can use this option to specify them. It should
be a string or list of strings specifying what other distributions need to be a string or list of strings specifying what other distributions need to
be present for the package's tests to run. When you run the ``test`` be present for the package's tests to run. When you run the ``test``
command, ``setuptools`` will attempt to obtain these. Note that these command, ``setuptools`` will attempt to obtain these (using pip if
required projects will *not* be installed on the system where the tests available). Note that these required projects will *not* be installed on
are run, but only downloaded to the project's setup directory if they're the system where the tests are run, but only downloaded to the project's setup
not already installed locally. directory if they're not already installed locally.
New in 41.5.0: Deprecated the test command. New in 41.5.0: Deprecated the test command.
......
"""Run the EasyInstall command"""
if __name__ == '__main__':
from setuptools.command.easy_install import main
main()
...@@ -51,7 +51,6 @@ classifiers = ...@@ -51,7 +51,6 @@ classifiers =
[options] [options]
zip_safe = True zip_safe = True
python_requires = >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* python_requires = >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
py_modules = easy_install
packages = find: packages = find:
[options.packages.find] [options.packages.find]
......
...@@ -31,22 +31,6 @@ def read_commands(): ...@@ -31,22 +31,6 @@ def read_commands():
return command_ns['__all__'] return command_ns['__all__']
def _gen_console_scripts():
yield "easy_install = setuptools.command.easy_install:main"
# Gentoo distributions manage the python-version-specific scripts
# themselves, so those platforms define an environment variable to
# suppress the creation of the version-specific scripts.
var_names = (
'SETUPTOOLS_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT',
'DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT',
)
if any(os.environ.get(var) not in (None, "", "0") for var in var_names):
return
tmpl = "easy_install-{shortver} = setuptools.command.easy_install:main"
yield tmpl.format(shortver='{}.{}'.format(*sys.version_info))
package_data = dict( package_data = dict(
setuptools=['script (dev).tmpl', 'script.tmpl', 'site-patch.py'], setuptools=['script (dev).tmpl', 'script.tmpl', 'site-patch.py'],
) )
...@@ -125,9 +109,6 @@ setup_params = dict( ...@@ -125,9 +109,6 @@ setup_params = dict(
"depends.txt = setuptools.command.egg_info:warn_depends_obsolete", "depends.txt = setuptools.command.egg_info:warn_depends_obsolete",
"dependency_links.txt = setuptools.command.egg_info:overwrite_arg", "dependency_links.txt = setuptools.command.egg_info:overwrite_arg",
], ],
"console_scripts": list(_gen_console_scripts()),
"setuptools.installation":
['eggsecutable = setuptools.command.easy_install:bootstrap'],
}, },
dependency_links=[ dependency_links=[
pypi_link( pypi_link(
......
...@@ -73,7 +73,7 @@ warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) ...@@ -73,7 +73,7 @@ warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
__all__ = [ __all__ = [
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
'main', 'get_exe_prefixes', 'get_exe_prefixes',
] ]
...@@ -410,7 +410,13 @@ class easy_install(Command): ...@@ -410,7 +410,13 @@ class easy_install(Command):
] ]
self._expand_attrs(dirs) self._expand_attrs(dirs)
def run(self): def run(self, show_deprecation=True):
if show_deprecation:
self.announce(
"WARNING: The easy_install command is deprecated "
"and will be removed in a future version."
, log.WARN,
)
if self.verbose != self.distribution.verbose: if self.verbose != self.distribution.verbose:
log.set_verbosity(self.verbose) log.set_verbosity(self.verbose)
try: try:
...@@ -2283,59 +2289,6 @@ def current_umask(): ...@@ -2283,59 +2289,6 @@ def current_umask():
return tmp return tmp
def bootstrap():
# This function is called when setuptools*.egg is run using /bin/sh
import setuptools
argv0 = os.path.dirname(setuptools.__path__[0])
sys.argv[0] = argv0
sys.argv.append(argv0)
main()
def main(argv=None, **kw):
from setuptools import setup
from setuptools.dist import Distribution
class DistributionWithoutHelpCommands(Distribution):
common_usage = ""
def _show_help(self, *args, **kw):
with _patch_usage():
Distribution._show_help(self, *args, **kw)
if argv is None:
argv = sys.argv[1:]
with _patch_usage():
setup(
script_args=['-q', 'easy_install', '-v'] + argv,
script_name=sys.argv[0] or 'easy_install',
distclass=DistributionWithoutHelpCommands,
**kw
)
@contextlib.contextmanager
def _patch_usage():
import distutils.core
USAGE = textwrap.dedent("""
usage: %(script)s [options] requirement_or_url ...
or: %(script)s --help
""").lstrip()
def gen_usage(script_name):
return USAGE % dict(
script=os.path.basename(script_name),
)
saved = distutils.core.gen_usage
distutils.core.gen_usage = gen_usage
try:
yield
finally:
distutils.core.gen_usage = saved
class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning): class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
"""Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning.""" """Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning."""
...@@ -114,7 +114,7 @@ class install(orig.install): ...@@ -114,7 +114,7 @@ class install(orig.install):
args.insert(0, setuptools.bootstrap_install_from) args.insert(0, setuptools.bootstrap_install_from)
cmd.args = args cmd.args = args
cmd.run() cmd.run(show_deprecation=False)
setuptools.bootstrap_install_from = None setuptools.bootstrap_install_from = None
......
...@@ -759,32 +759,8 @@ class Distribution(_Distribution): ...@@ -759,32 +759,8 @@ class Distribution(_Distribution):
def fetch_build_egg(self, req): def fetch_build_egg(self, req):
"""Fetch an egg needed for building""" """Fetch an egg needed for building"""
from setuptools.command.easy_install import easy_install from setuptools.installer import fetch_build_egg
dist = self.__class__({'script_args': ['easy_install']}) return fetch_build_egg(self, req)
opts = dist.get_option_dict('easy_install')
opts.clear()
opts.update(
(k, v)
for k, v in self.get_option_dict('easy_install').items()
if k in (
# don't use any other settings
'find_links', 'site_dirs', 'index_url',
'optimize', 'site_dirs', 'allow_hosts',
))
if self.dependency_links:
links = self.dependency_links[:]
if 'find_links' in opts:
links = opts['find_links'][1] + links
opts['find_links'] = ('setup', links)
install_dir = self.get_egg_cache_dir()
cmd = easy_install(
dist, args=["x"], install_dir=install_dir,
exclude_scripts=True,
always_copy=False, build_directory=None, editable=False,
upgrade=False, multi_version=True, no_report=True, user=False
)
cmd.ensure_finalized()
return cmd.easy_install(req)
def _set_global_opts_from_features(self): def _set_global_opts_from_features(self):
"""Add --with-X/--without-X options based on optional features""" """Add --with-X/--without-X options based on optional features"""
......
import glob
import os
import subprocess
import sys
from distutils import log
from distutils.errors import DistutilsError
import pkg_resources
from setuptools.command.easy_install import easy_install
from setuptools.wheel import Wheel
from .py31compat import TemporaryDirectory
def _legacy_fetch_build_egg(dist, req):
"""Fetch an egg needed for building.
Legacy path using EasyInstall.
"""
tmp_dist = dist.__class__({'script_args': ['easy_install']})
opts = tmp_dist.get_option_dict('easy_install')
opts.clear()
opts.update(
(k, v)
for k, v in dist.get_option_dict('easy_install').items()
if k in (
# don't use any other settings
'find_links', 'site_dirs', 'index_url',
'optimize', 'site_dirs', 'allow_hosts',
))
if dist.dependency_links:
links = dist.dependency_links[:]
if 'find_links' in opts:
links = opts['find_links'][1] + links
opts['find_links'] = ('setup', links)
install_dir = dist.get_egg_cache_dir()
cmd = easy_install(
tmp_dist, args=["x"], install_dir=install_dir,
exclude_scripts=True,
always_copy=False, build_directory=None, editable=False,
upgrade=False, multi_version=True, no_report=True, user=False
)
cmd.ensure_finalized()
return cmd.easy_install(req)
def fetch_build_egg(dist, req):
"""Fetch an egg needed for building.
Use pip/wheel to fetch/build a wheel."""
# Check pip is available.
try:
pkg_resources.get_distribution('pip')
except pkg_resources.DistributionNotFound:
dist.announce(
'WARNING: The pip package is not available, falling back '
'to EasyInstall for handling setup_requires/test_requires; '
'this is deprecated and will be removed in a future version.'
, log.WARN
)
return _legacy_fetch_build_egg(dist, req)
# Warn if wheel is not.
try:
pkg_resources.get_distribution('wheel')
except pkg_resources.DistributionNotFound:
dist.announce('WARNING: The wheel package is not available.', log.WARN)
if not isinstance(req, pkg_resources.Requirement):
req = pkg_resources.Requirement.parse(req)
# Take easy_install options into account, but do not override relevant
# pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll
# take precedence.
opts = dist.get_option_dict('easy_install')
if 'allow_hosts' in opts:
raise DistutilsError('the `allow-hosts` option is not supported '
'when using pip to install requirements.')
if 'PIP_QUIET' in os.environ or 'PIP_VERBOSE' in os.environ:
quiet = False
else:
quiet = True
if 'PIP_INDEX_URL' in os.environ:
index_url = None
elif 'index_url' in opts:
index_url = opts['index_url'][1]
else:
index_url = None
if 'find_links' in opts:
find_links = opts['find_links'][1][:]
else:
find_links = []
if dist.dependency_links:
find_links.extend(dist.dependency_links)
eggs_dir = os.path.realpath(dist.get_egg_cache_dir())
environment = pkg_resources.Environment()
for egg_dist in pkg_resources.find_distributions(eggs_dir):
if egg_dist in req and environment.can_add(egg_dist):
return egg_dist
with TemporaryDirectory() as tmpdir:
cmd = [
sys.executable, '-m', 'pip',
'--disable-pip-version-check',
'wheel', '--no-deps',
'-w', tmpdir,
]
if quiet:
cmd.append('--quiet')
if index_url is not None:
cmd.extend(('--index-url', index_url))
if find_links is not None:
for link in find_links:
cmd.extend(('--find-links', link))
# If requirement is a PEP 508 direct URL, directly pass
# the URL to pip, as `req @ url` does not work on the
# command line.
if req.url:
cmd.append(req.url)
else:
cmd.append(str(req))
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError as e:
raise DistutilsError(str(e))
wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0])
dist_location = os.path.join(eggs_dir, wheel.egg_name())
wheel.install_as_egg(dist_location)
dist_metadata = pkg_resources.PathMetadata(
dist_location, os.path.join(dist_location, 'EGG-INFO'))
dist = pkg_resources.Distribution.from_filename(
dist_location, metadata=dist_metadata)
return dist
"""Basic http server for tests to simulate PyPI or custom indexes """Basic http server for tests to simulate PyPI or custom indexes
""" """
import os
import time import time
import threading import threading
from setuptools.extern.six.moves import BaseHTTPServer, SimpleHTTPServer from setuptools.extern.six.moves import BaseHTTPServer, SimpleHTTPServer
from setuptools.extern.six.moves.urllib_parse import urljoin
from setuptools.extern.six.moves.urllib.request import pathname2url
class IndexServer(BaseHTTPServer.HTTPServer): class IndexServer(BaseHTTPServer.HTTPServer):
...@@ -69,6 +72,20 @@ class MockServer(BaseHTTPServer.HTTPServer, threading.Thread): ...@@ -69,6 +72,20 @@ class MockServer(BaseHTTPServer.HTTPServer, threading.Thread):
def run(self): def run(self):
self.serve_forever() self.serve_forever()
@property
def netloc(self):
return 'localhost:%s' % self.server_port
@property @property
def url(self): def url(self):
return 'http://localhost:%(server_port)s/' % vars(self) return 'http://%s/' % self.netloc
def path_to_url(path, authority=None):
""" Convert a path to a file: URL. """
path = os.path.normpath(os.path.abspath(path))
base = 'file:'
if authority is not None:
base += '//' + authority
url = urljoin(base, pathname2url(path))
return url
This diff is collapsed.
...@@ -64,9 +64,8 @@ class TestNamespaces: ...@@ -64,9 +64,8 @@ class TestNamespaces:
target.mkdir() target.mkdir()
install_cmd = [ install_cmd = [
sys.executable, sys.executable,
'-m', 'easy_install', '-m', 'pip.__main__', 'install',
'-d', str(target), '-t', str(target), str(pkg),
str(pkg),
] ]
with test.test.paths_on_pythonpath([str(target)]): with test.test.paths_on_pythonpath([str(target)]):
subprocess.check_call(install_cmd) subprocess.check_call(install_cmd)
......
...@@ -121,14 +121,12 @@ def test_pip_upgrade_from_source(pip_version, virtualenv): ...@@ -121,14 +121,12 @@ def test_pip_upgrade_from_source(pip_version, virtualenv):
virtualenv.run('pip install --no-cache-dir --upgrade ' + sdist) virtualenv.run('pip install --no-cache-dir --upgrade ' + sdist)
def test_test_command_install_requirements(bare_virtualenv, tmpdir): def _check_test_command_install_requirements(virtualenv, tmpdir):
""" """
Check the test command will install all required dependencies. Check the test command will install all required dependencies.
""" """
bare_virtualenv.run(' && '.join(( # Install setuptools.
'cd {source}', virtualenv.run('python setup.py develop', cd=SOURCE_DIR)
'python setup.py develop',
)).format(source=SOURCE_DIR))
def sdist(distname, version): def sdist(distname, version):
dist_path = tmpdir.join('%s-%s.tar.gz' % (distname, version)) dist_path = tmpdir.join('%s-%s.tar.gz' % (distname, version))
...@@ -179,12 +177,20 @@ def test_test_command_install_requirements(bare_virtualenv, tmpdir): ...@@ -179,12 +177,20 @@ def test_test_command_install_requirements(bare_virtualenv, tmpdir):
open('success', 'w').close() open('success', 'w').close()
''')) '''))
# Run test command for test package. # Run test command for test package.
bare_virtualenv.run(' && '.join(( virtualenv.run(' && '.join((
'cd {tmpdir}', 'cd {tmpdir}',
'python setup.py test -s test', 'python setup.py test -s test',
)).format(tmpdir=tmpdir)) )).format(tmpdir=tmpdir))
assert tmpdir.join('success').check() assert tmpdir.join('success').check()
def test_test_command_install_requirements(virtualenv, tmpdir):
# Ensure pip/wheel packages are installed.
virtualenv.run("python -c \"__import__('pkg_resources').require(['pip', 'wheel'])\"")
_check_test_command_install_requirements(virtualenv, tmpdir)
def test_test_command_install_requirements_when_using_easy_install(bare_virtualenv, tmpdir):
_check_test_command_install_requirements(bare_virtualenv, tmpdir)
def test_no_missing_dependencies(bare_virtualenv): def test_no_missing_dependencies(bare_virtualenv):
""" """
......
...@@ -9,3 +9,4 @@ coverage>=4.5.1 ...@@ -9,3 +9,4 @@ coverage>=4.5.1
pytest-cov>=2.5.1 pytest-cov>=2.5.1
paver; python_version>="3.6" paver; python_version>="3.6"
futures; python_version=="2.7" futures; python_version=="2.7"
pip>=19.1 # For proper file:// URLs support.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment