Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-95299: Stop installing setuptools as a part of ensurepip and venv #101039

Merged
merged 21 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
001ee43
Use environment variables to pass data into test setup script
pradyunsg Jan 14, 2023
b8421a1
Update test_cppext to stop invoking setuptools-based script as a CLI
pradyunsg Jan 14, 2023
9d343f2
Stop installing setuptools as a part of ensurepip and venv
pradyunsg Sep 24, 2022
4a51332
Correct the name of step in GitHub Action
pradyunsg Jan 15, 2023
e0c53df
Drop most remaining references to `easy_install`
pradyunsg Feb 3, 2023
4c8e6be
fixup! Update test_cppext to stop invoking setuptools-based script as…
pradyunsg Feb 3, 2023
b489e52
fixup! Update test_cppext to stop invoking setuptools-based script as…
pradyunsg Feb 3, 2023
f308da4
Add a "What's New" entry for the setuptools removal
pradyunsg Feb 3, 2023
9579a3e
fixup! Add a "What's New" entry for the setuptools removal
pradyunsg Feb 3, 2023
0e2b55e
fixup! Add a "What's New" entry for the setuptools removal
pradyunsg Feb 3, 2023
0b8f384
Update Doc/whatsnew/3.12.rst
pradyunsg Feb 4, 2023
1262bee
Merge branch 'main' into remove-setuptools-ensurepip
arhadthedev Feb 23, 2023
bcda4cd
Merge branch 'main' into remove-setuptools-ensurepip
pradyunsg Feb 26, 2023
e19784d
Update "Creating virtual environments" section to drop reference
pradyunsg Apr 4, 2023
ea1bcea
Use the style suggested in review
pradyunsg Apr 4, 2023
5275f93
Use dirname on the absolute path
pradyunsg Apr 4, 2023
5c3ce99
Locate cppextdata with plain filesystem lookups
pradyunsg Apr 4, 2023
375b5c6
Merge branch 'main' into remove-setuptools-ensurepip
pradyunsg Apr 17, 2023
991d066
bundled pip -> bundled wheels
pradyunsg Apr 17, 2023
ebf6c3b
Unbreak `test_cppext`
pradyunsg Apr 17, 2023
b83cf9f
:art:
pradyunsg Apr 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/verify-ensurepip-wheels.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Verify bundled pip and setuptools
name: Verify bundled pip
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved

on:
workflow_dispatch:
Expand Down Expand Up @@ -28,5 +28,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 pip to the one published on PyPI
run: ./Tools/build/verify_ensurepip_wheels.py
7 changes: 5 additions & 2 deletions Doc/library/venv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
18 changes: 18 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,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:
Expand Down
16 changes: 7 additions & 9 deletions Lib/ensurepip/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@


__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"),
]

Expand Down Expand Up @@ -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
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
#
# 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:
Expand Down Expand Up @@ -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)
Expand Down
Binary file not shown.
11 changes: 3 additions & 8 deletions Lib/test/setup_testcppext.py → Lib/test/cppextdata/setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# gh-91321: Build a basic C++ test extension to check that the Python C API is
# compatible with C++ and does not emit C++ compiler warnings.
import os
import sys
from test import support

Expand All @@ -25,14 +26,8 @@

def main():
cppflags = list(CPPFLAGS)
if '-std=c++03' in sys.argv:
sys.argv.remove('-std=c++03')
std = 'c++03'
name = '_testcpp03ext'
else:
# Python currently targets C++11
std = 'c++11'
name = '_testcpp11ext'
std = os.environ["CPYTHON_TEST_CPP_STD"]
name = os.environ["CPYTHON_TEST_EXT_NAME"]

cppflags = [*CPPFLAGS, f'-std={std}']

Expand Down
27 changes: 16 additions & 11 deletions Lib/test/test_cppext.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# gh-91321: Build a basic C++ test extension to check that the Python C API is
# compatible with C++ and does not emit C++ compiler warnings.
import os.path
try:
import ssl
except ImportError:
ssl = None
import sys
import unittest
import subprocess
Expand All @@ -12,7 +16,9 @@
MS_WINDOWS = (sys.platform == 'win32')


SETUP_TESTCPPEXT = support.findfile('setup_testcppext.py')
PKG_CPPEXTDATA = os.path.abspath(os.path.dirname(
support.findfile('setup.py', subdir="cppextdata")
))


@support.requires_subprocess()
Expand All @@ -31,6 +37,8 @@ def test_build_cpp03(self):
@unittest.skipIf(
'-fsanitize' in (sysconfig.get_config_var('PY_CFLAGS') or ''),
'test does not work with analyzing builds')
# the test uses pip which needs a TLS connection to PyPI
@unittest.skipIf(ssl is None, 'No ssl module')
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
# the test uses venv+pip: skip if it's not available
@support.requires_venv_with_pip()
def check_build(self, std_cpp03, extension_name):
Expand Down Expand Up @@ -59,11 +67,15 @@ def _check_build(self, std_cpp03, extension_name):
python = os.path.join(venv_dir, 'bin', python_exe)

def run_cmd(operation, cmd):
env = os.environ.copy()
env['CPYTHON_TEST_CPP_STD'] = 'c++03' if std_cpp03 else 'c++11'
env['CPYTHON_TEST_EXT_NAME'] = extension_name
if verbose:
print('Run:', ' '.join(cmd))
subprocess.run(cmd, check=True)
subprocess.run(cmd, check=True, env=env)
else:
proc = subprocess.run(cmd,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True)
Expand All @@ -72,16 +84,9 @@ def run_cmd(operation, cmd):
self.fail(
f"{operation} failed with exit code {proc.returncode}")

# Build the C++ extension
# Build and install the C++ extension
cmd = [python, '-X', 'dev',
SETUP_TESTCPPEXT, 'build_ext', '--verbose']
if std_cpp03:
cmd.append('-std=c++03')
run_cmd('Build', cmd)

# Install the C++ extension
cmd = [python, '-X', 'dev',
SETUP_TESTCPPEXT, 'install']
'-m', 'pip', 'install', PKG_CPPEXTDATA]
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
run_cmd('Install', cmd)

# Do a reference run. Until we test that running python
Expand Down
35 changes: 12 additions & 23 deletions Lib/test/test_ensurepip.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def test_version(self):
# 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')
Expand All @@ -36,15 +35,12 @@ def test_get_packages_no_dir(self):

# 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")
Expand All @@ -53,15 +49,12 @@ def test_get_packages_with_dir(self):
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:
Expand Down Expand Up @@ -92,13 +85,13 @@ def test_basic_bootstrapping(self):
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/")
Expand All @@ -107,7 +100,7 @@ def test_bootstrapping_with_root(self):
[
"install", "--no-cache-dir", "--no-index", "--find-links",
unittest.mock.ANY, "--root", "/foo/bar/",
"setuptools", "pip",
"pip",
],
unittest.mock.ANY,
)
Expand All @@ -118,7 +111,7 @@ def test_bootstrapping_with_user(self):
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,
)
Expand All @@ -129,7 +122,7 @@ def test_bootstrapping_with_upgrade(self):
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,
)
Expand All @@ -140,7 +133,7 @@ def test_bootstrapping_with_verbosity_1(self):
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,
)
Expand All @@ -151,7 +144,7 @@ def test_bootstrapping_with_verbosity_2(self):
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,
)
Expand All @@ -162,7 +155,7 @@ def test_bootstrapping_with_verbosity_3(self):
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,
)
Expand Down Expand Up @@ -239,7 +232,6 @@ def test_uninstall(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "pip",
"setuptools",
]
)

Expand All @@ -250,7 +242,6 @@ def test_uninstall_with_verbosity_1(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "-v", "pip",
"setuptools",
]
)

Expand All @@ -261,7 +252,6 @@ def test_uninstall_with_verbosity_2(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "-vv", "pip",
"setuptools",
]
)

Expand All @@ -272,7 +262,7 @@ def test_uninstall_with_verbosity_3(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "-vvv",
"pip", "setuptools",
"pip"
]
)

Expand Down Expand Up @@ -312,13 +302,13 @@ def test_basic_bootstrapping(self):
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):
Expand All @@ -344,7 +334,6 @@ def test_basic_uninstall(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "pip",
"setuptools",
]
)

Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ def pip_cmd_checker(cmd, **kwargs):
'install',
'--upgrade',
'pip',
'setuptools'
]
)

Expand Down Expand Up @@ -729,7 +728,6 @@ def do_test_with_pip(self, system_site_packages):
# 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
Expand Down
2 changes: 1 addition & 1 deletion Lib/venv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import types


CORE_VENV_DEPS = ('pip', 'setuptools')
CORE_VENV_DEPS = ('pip',)
logger = logging.getLogger(__name__)


Expand Down
Loading