From ece20dba120a1a4745721c49f8d7389d4b1ee2a7 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Mon, 17 Apr 2023 23:43:34 -0500 Subject: gh-95299: Stop installing setuptools as a part of ensurepip and venv (#101039) Remove the bundled setuptools wheel from ensurepip, and stop installing setuptools in environments created by venv. Co-Authored-by: Hugo van Kemenade Co-authored-by: C.A.M. Gerlach Co-authored-by: Oleg Iarygin --- .github/workflows/verify-ensurepip-wheels.yml | 4 +-- Doc/library/venv.rst | 7 +++-- Doc/using/venv-create.inc | 7 +++-- Doc/whatsnew/3.12.rst | 18 +++++++++++ Lib/ensurepip/__init__.py | 16 +++++----- .../_bundled/setuptools-65.5.0-py3-none-any.whl | Bin 1232695 -> 0 bytes Lib/test/test_ensurepip.py | 35 +++++++-------------- Lib/test/test_venv.py | 2 -- Lib/venv/__init__.py | 4 +-- Mac/BuildScript/scripts/postflight.ensurepip | 8 ++--- Mac/Makefile.in | 1 - .../2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst | 1 + Tools/build/verify_ensurepip_wheels.py | 2 +- 13 files changed, 57 insertions(+), 48 deletions(-) delete mode 100644 Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl create mode 100644 Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index d4a2cb6..17d841f 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -1,4 +1,4 @@ -name: Verify bundled pip and setuptools +name: Verify bundled wheels on: workflow_dispatch: @@ -29,5 +29,5 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3' - - name: Compare checksums of bundled pip and setuptools to ones published on PyPI + - name: Compare checksum of bundled wheels to the ones published on PyPI run: ./Tools/build/verify_ensurepip_wheels.py diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 240ab13..52bf99e 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -284,11 +284,14 @@ creation according to their needs, the :class:`EnvBuilder` class. .. method:: upgrade_dependencies(context) - Upgrades the core venv dependency packages (currently ``pip`` and - ``setuptools``) in the environment. This is done by shelling out to the + Upgrades the core venv dependency packages (currently ``pip``) + in the environment. This is done by shelling out to the ``pip`` executable in the environment. .. versionadded:: 3.9 + .. versionchanged:: 3.12 + + ``setuptools`` is no longer a core venv dependency. .. method:: post_setup(context) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index 43ee6b7..2fc9012 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -61,12 +61,16 @@ The command, if run with ``-h``, will show the available options:: environment (pip is bootstrapped by default) --prompt PROMPT Provides an alternative prompt prefix for this environment. - --upgrade-deps Upgrade core dependencies: pip setuptools to the + --upgrade-deps Upgrade core dependencies (pip) to the latest version in PyPI Once an environment has been created, you may wish to activate it, e.g. by sourcing an activate script in its bin directory. +.. versionchanged:: 3.12 + + ``setuptools`` is no longer a core venv dependency. + .. versionchanged:: 3.9 Add ``--upgrade-deps`` option to upgrade pip + setuptools to the latest on PyPI @@ -104,4 +108,3 @@ invoked to bootstrap ``pip`` into the virtual environment. Multiple paths can be given to ``venv``, in which case an identical virtual environment will be created, according to the given options, at each provided path. - diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 2a371eb..bd95bfe 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -731,6 +731,24 @@ Removed project can be installed: it still provides ``distutils``. (Contributed by Victor Stinner in :gh:`92584`.) +* Remove the bundled setuptools wheel from :mod:`ensurepip`, + and stop installing setuptools in environments created by :mod:`venv`. + + ``pip (>= 22.1)`` does not require setuptools to be installed in the + environment. ``setuptools``-based (and ``distutils``-based) packages + can still be used with ``pip install``, since pip will provide + ``setuptools`` in the build environment it uses for building a + package. + + ``easy_install``, ``pkg_resources``, ``setuptools`` and ``distutils`` + are no longer provided by default in environments created with + ``venv`` or bootstrapped with ``ensurepip``, since they are part of + the ``setuptools`` package. For projects relying on these at runtime, + the ``setuptools`` project should be declared as a dependency and + installed separately (typically, using pip). + + (Contributed by Pradyun Gedam in :gh:`95299`.) + * Removed many old deprecated :mod:`unittest` features: - A number of :class:`~unittest.TestCase` method aliases: diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 00e7774..69b23de 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -9,11 +9,9 @@ from importlib import resources __all__ = ["version", "bootstrap"] -_PACKAGE_NAMES = ('setuptools', 'pip') -_SETUPTOOLS_VERSION = "65.5.0" +_PACKAGE_NAMES = ('pip',) _PIP_VERSION = "23.0.1" _PROJECTS = [ - ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), ] @@ -153,17 +151,17 @@ def _bootstrap(*, root=None, upgrade=False, user=False, _disable_pip_configuration_settings() - # By default, installing pip and setuptools installs all of the + # By default, installing pip installs all of the # following scripts (X.Y == running Python version): # - # pip, pipX, pipX.Y, easy_install, easy_install-X.Y + # pip, pipX, pipX.Y # # pip 1.5+ allows ensurepip to request that some of those be left out if altinstall: - # omit pip, pipX and easy_install + # omit pip, pipX os.environ["ENSUREPIP_OPTIONS"] = "altinstall" elif not default_pip: - # omit pip and easy_install + # omit pip os.environ["ENSUREPIP_OPTIONS"] = "install" with tempfile.TemporaryDirectory() as tmpdir: @@ -271,14 +269,14 @@ def _main(argv=None): action="store_true", default=False, help=("Make an alternate install, installing only the X.Y versioned " - "scripts (Default: pipX, pipX.Y, easy_install-X.Y)."), + "scripts (Default: pipX, pipX.Y)."), ) parser.add_argument( "--default-pip", action="store_true", default=False, help=("Make a default pip install, installing the unqualified pip " - "and easy_install in addition to the versioned scripts."), + "in addition to the versioned scripts."), ) args = parser.parse_args(argv) diff --git a/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl deleted file mode 100644 index 123a13e..0000000 Binary files a/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl and /dev/null differ diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index bfca0cd..69ab2a4 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -20,7 +20,6 @@ class TestPackages(unittest.TestCase): # Test version() with tempfile.TemporaryDirectory() as tmpdir: self.touch(tmpdir, "pip-1.2.3b1-py2.py3-none-any.whl") - self.touch(tmpdir, "setuptools-49.1.3-py3-none-any.whl") with (unittest.mock.patch.object(ensurepip, '_PACKAGES', None), unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)): self.assertEqual(ensurepip.version(), '1.2.3b1') @@ -36,15 +35,12 @@ class TestPackages(unittest.TestCase): # use bundled wheel packages self.assertIsNotNone(packages['pip'].wheel_name) - self.assertIsNotNone(packages['setuptools'].wheel_name) def test_get_packages_with_dir(self): # Test _get_packages() with a wheel package directory - setuptools_filename = "setuptools-49.1.3-py3-none-any.whl" pip_filename = "pip-20.2.2-py2.py3-none-any.whl" with tempfile.TemporaryDirectory() as tmpdir: - self.touch(tmpdir, setuptools_filename) self.touch(tmpdir, pip_filename) # not used, make sure that it's ignored self.touch(tmpdir, "wheel-0.34.2-py2.py3-none-any.whl") @@ -53,15 +49,12 @@ class TestPackages(unittest.TestCase): unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)): packages = ensurepip._get_packages() - self.assertEqual(packages['setuptools'].version, '49.1.3') - self.assertEqual(packages['setuptools'].wheel_path, - os.path.join(tmpdir, setuptools_filename)) self.assertEqual(packages['pip'].version, '20.2.2') self.assertEqual(packages['pip'].wheel_path, os.path.join(tmpdir, pip_filename)) # wheel package is ignored - self.assertEqual(sorted(packages), ['pip', 'setuptools']) + self.assertEqual(sorted(packages), ['pip']) class EnsurepipMixin: @@ -92,13 +85,13 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "setuptools", "pip", + unittest.mock.ANY, "pip", ], unittest.mock.ANY, ) additional_paths = self.run_pip.call_args[0][1] - self.assertEqual(len(additional_paths), 2) + self.assertEqual(len(additional_paths), 1) def test_bootstrapping_with_root(self): ensurepip.bootstrap(root="/foo/bar/") @@ -107,7 +100,7 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): [ "install", "--no-cache-dir", "--no-index", "--find-links", unittest.mock.ANY, "--root", "/foo/bar/", - "setuptools", "pip", + "pip", ], unittest.mock.ANY, ) @@ -118,7 +111,7 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "--user", "setuptools", "pip", + unittest.mock.ANY, "--user", "pip", ], unittest.mock.ANY, ) @@ -129,7 +122,7 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "--upgrade", "setuptools", "pip", + unittest.mock.ANY, "--upgrade", "pip", ], unittest.mock.ANY, ) @@ -140,7 +133,7 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "-v", "setuptools", "pip", + unittest.mock.ANY, "-v", "pip", ], unittest.mock.ANY, ) @@ -151,7 +144,7 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "-vv", "setuptools", "pip", + unittest.mock.ANY, "-vv", "pip", ], unittest.mock.ANY, ) @@ -162,7 +155,7 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "-vvv", "setuptools", "pip", + unittest.mock.ANY, "-vvv", "pip", ], unittest.mock.ANY, ) @@ -239,7 +232,6 @@ class TestUninstall(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "pip", - "setuptools", ] ) @@ -250,7 +242,6 @@ class TestUninstall(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "-v", "pip", - "setuptools", ] ) @@ -261,7 +252,6 @@ class TestUninstall(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "-vv", "pip", - "setuptools", ] ) @@ -272,7 +262,7 @@ class TestUninstall(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "-vvv", - "pip", "setuptools", + "pip" ] ) @@ -312,13 +302,13 @@ class TestBootstrappingMainFunction(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "setuptools", "pip", + unittest.mock.ANY, "pip", ], unittest.mock.ANY, ) additional_paths = self.run_pip.call_args[0][1] - self.assertEqual(len(additional_paths), 2) + self.assertEqual(len(additional_paths), 1) self.assertEqual(exit_code, 0) def test_bootstrapping_error_code(self): @@ -344,7 +334,6 @@ class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "pip", - "setuptools", ] ) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 7cccbe8..333b976 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -227,7 +227,6 @@ class BasicTest(BaseTest): 'install', '--upgrade', 'pip', - 'setuptools' ] ) @@ -745,7 +744,6 @@ class EnsurePipTest(BaseTest): # future pip versions, this test can likely be relaxed further. out = out.decode("latin-1") # Force to text, prevent decoding errors self.assertIn("Successfully uninstalled pip", out) - self.assertIn("Successfully uninstalled setuptools", out) # Check pip is now gone from the virtual environment. This only # applies in the system_site_packages=False case, because in the # other case, pip may still be available in the system site-packages diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 2f87c62..2173c9b 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -13,7 +13,7 @@ import sysconfig import types -CORE_VENV_DEPS = ('pip', 'setuptools') +CORE_VENV_DEPS = ('pip',) logger = logging.getLogger(__name__) @@ -523,7 +523,7 @@ def main(args=None): 'this environment.') parser.add_argument('--upgrade-deps', default=False, action='store_true', dest='upgrade_deps', - help=f'Upgrade core dependencies: {", ".join(CORE_VENV_DEPS)} ' + help=f'Upgrade core dependencies ({", ".join(CORE_VENV_DEPS)}) ' 'to the latest version in PyPI') options = parser.parse_args(args) if options.upgrade and options.clear: diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip index 36d0594..ce3c6c1 100755 --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -56,19 +56,19 @@ if [ -d /usr/local/bin ] ; then cd /usr/local/bin - # Create pipx.y and easy_install-x.y links if /usr/local/bin/pythonx.y + # Create pipx.y links if /usr/local/bin/pythonx.y # is linked to this framework version install_links_if_our_fw "python${PYVER}" \ - "pip${PYVER}" "easy_install-${PYVER}" + "pip${PYVER}" # Create pipx link if /usr/local/bin/pythonx is linked to this version install_links_if_our_fw "python${PYMAJOR}" \ "pip${PYMAJOR}" - # Create pip and easy_install link if /usr/local/bin/python + # Create pip link if /usr/local/bin/python # is linked to this version install_links_if_our_fw "python" \ - "pip" "easy_install" + "pip" ) fi exit 0 diff --git a/Mac/Makefile.in b/Mac/Makefile.in index f969128..69ab419 100644 --- a/Mac/Makefile.in +++ b/Mac/Makefile.in @@ -166,7 +166,6 @@ altinstallunixtools: -if test "x$(ENSUREPIP)" != "xno" ; then \ cd "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" && \ for fn in \ - easy_install-$(VERSION) \ pip$(VERSION) \ ; \ do \ diff --git a/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst b/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst new file mode 100644 index 0000000..29c3084 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst @@ -0,0 +1 @@ +Remove the bundled setuptools wheel from ``ensurepip``, and stop installing setuptools in environments created by ``venv``. diff --git a/Tools/build/verify_ensurepip_wheels.py b/Tools/build/verify_ensurepip_wheels.py index 044d1fd..09fd5d9 100755 --- a/Tools/build/verify_ensurepip_wheels.py +++ b/Tools/build/verify_ensurepip_wheels.py @@ -14,7 +14,7 @@ import re from pathlib import Path from urllib.request import urlopen -PACKAGE_NAMES = ("pip", "setuptools") +PACKAGE_NAMES = ("pip",) ENSURE_PIP_ROOT = Path(__file__).parent.parent.parent / "Lib/ensurepip" WHEEL_DIR = ENSURE_PIP_ROOT / "_bundled" ENSURE_PIP_INIT_PY_TEXT = (ENSURE_PIP_ROOT / "__init__.py").read_text(encoding="utf-8") -- cgit v0.12