mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	Close #19552: venv and pyvenv ensurepip integration
This commit is contained in:
		
							parent
							
								
									0b61ef6f79
								
							
						
					
					
						commit
						8fbdb097cf
					
				
					 5 changed files with 105 additions and 13 deletions
				
			
		| 
						 | 
					@ -85,7 +85,8 @@ The high-level method described above makes use of a simple API which provides
 | 
				
			||||||
mechanisms for third-party virtual environment creators to customize environment
 | 
					mechanisms for third-party virtual environment creators to customize environment
 | 
				
			||||||
creation according to their needs, the :class:`EnvBuilder` class.
 | 
					creation according to their needs, the :class:`EnvBuilder` class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. class:: EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False)
 | 
					.. class:: EnvBuilder(system_site_packages=False, clear=False, \
 | 
				
			||||||
 | 
					                      symlinks=False, upgrade=False, with_pip=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    The :class:`EnvBuilder` class accepts the following keyword arguments on
 | 
					    The :class:`EnvBuilder` class accepts the following keyword arguments on
 | 
				
			||||||
    instantiation:
 | 
					    instantiation:
 | 
				
			||||||
| 
						 | 
					@ -105,6 +106,12 @@ creation according to their needs, the :class:`EnvBuilder` class.
 | 
				
			||||||
      environment with the running Python - for use when that Python has been
 | 
					      environment with the running Python - for use when that Python has been
 | 
				
			||||||
      upgraded in-place (defaults to ``False``).
 | 
					      upgraded in-place (defaults to ``False``).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    * ``with_pip`` -- a Boolean value which, if True, ensures pip is
 | 
				
			||||||
 | 
					      installed in the virtual environment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. versionchanged:: 3.4
 | 
				
			||||||
 | 
					       Added the ``with_pip`` parameter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Creators of third-party virtual environment tools will be free to use the
 | 
					    Creators of third-party virtual environment tools will be free to use the
 | 
				
			||||||
    provided ``EnvBuilder`` class as a base class.
 | 
					    provided ``EnvBuilder`` class as a base class.
 | 
				
			||||||
| 
						 | 
					@ -201,11 +208,15 @@ creation according to their needs, the :class:`EnvBuilder` class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There is also a module-level convenience function:
 | 
					There is also a module-level convenience function:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. function:: create(env_dir, system_site_packages=False, clear=False, symlinks=False)
 | 
					.. function:: create(env_dir, system_site_packages=False, clear=False, \
 | 
				
			||||||
 | 
					                     symlinks=False, with_pip=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Create an :class:`EnvBuilder` with the given keyword arguments, and call its
 | 
					    Create an :class:`EnvBuilder` with the given keyword arguments, and call its
 | 
				
			||||||
    :meth:`~EnvBuilder.create` method with the *env_dir* argument.
 | 
					    :meth:`~EnvBuilder.create` method with the *env_dir* argument.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. versionchanged:: 3.4
 | 
				
			||||||
 | 
					       Added the ``with_pip`` parameter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
An example of extending ``EnvBuilder``
 | 
					An example of extending ``EnvBuilder``
 | 
				
			||||||
--------------------------------------
 | 
					--------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,7 @@ or equivalently::
 | 
				
			||||||
The command, if run with ``-h``, will show the available options::
 | 
					The command, if run with ``-h``, will show the available options::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear]
 | 
					    usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear]
 | 
				
			||||||
                  [--upgrade] ENV_DIR [ENV_DIR ...]
 | 
					                  [--upgrade] [--without-pip] ENV_DIR [ENV_DIR ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Creates virtual Python environments in one or more target directories.
 | 
					    Creates virtual Python environments in one or more target directories.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,11 @@ The command, if run with ``-h``, will show the available options::
 | 
				
			||||||
                             raised.
 | 
					                             raised.
 | 
				
			||||||
      --upgrade              Upgrade the environment directory to use this version
 | 
					      --upgrade              Upgrade the environment directory to use this version
 | 
				
			||||||
                             of Python, assuming Python has been upgraded in-place.
 | 
					                             of Python, assuming Python has been upgraded in-place.
 | 
				
			||||||
 | 
					      --without-pip          Skips installing or upgrading pip in the virtual
 | 
				
			||||||
 | 
					                             environment (pip is bootstrapped by default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. versionchanged:: 3.4
 | 
				
			||||||
 | 
					   Installs pip by default, added the ``--without-pip`` option
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If the target directory already exists an error will be raised, unless
 | 
					If the target directory already exists an error will be raised, unless
 | 
				
			||||||
the ``--clear`` or ``--upgrade`` option was provided.
 | 
					the ``--clear`` or ``--upgrade`` option was provided.
 | 
				
			||||||
| 
						 | 
					@ -51,6 +56,9 @@ The created ``pyvenv.cfg`` file also includes the
 | 
				
			||||||
``include-system-site-packages`` key, set to ``true`` if ``venv`` is
 | 
					``include-system-site-packages`` key, set to ``true`` if ``venv`` is
 | 
				
			||||||
run with the ``--system-site-packages`` option, ``false`` otherwise.
 | 
					run with the ``--system-site-packages`` option, ``false`` otherwise.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless the ``--without-pip`` option is given, :mod:`ensurepip` will be
 | 
				
			||||||
 | 
					invoked to bootstrap ``pip`` into the virtual environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Multiple paths can be given to ``pyvenv``, in which case an identical
 | 
					Multiple paths can be given to ``pyvenv``, in which case an identical
 | 
				
			||||||
virtualenv will be created, according to the given options, at each
 | 
					virtualenv will be created, according to the given options, at each
 | 
				
			||||||
provided path.
 | 
					provided path.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,10 @@ from test.support import (captured_stdout, captured_stderr, run_unittest,
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
import venv
 | 
					import venv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					skipInVenv = unittest.skipIf(sys.prefix != sys.base_prefix,
 | 
				
			||||||
 | 
					                             'Test not appropriate in a venv')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BaseTest(unittest.TestCase):
 | 
					class BaseTest(unittest.TestCase):
 | 
				
			||||||
    """Base class for venv tests."""
 | 
					    """Base class for venv tests."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,8 +87,7 @@ class BasicTest(BaseTest):
 | 
				
			||||||
            print('    %r' % os.listdir(bd))
 | 
					            print('    %r' % os.listdir(bd))
 | 
				
			||||||
        self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
 | 
					        self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate '
 | 
					    @skipInVenv
 | 
				
			||||||
                     'in a venv')
 | 
					 | 
				
			||||||
    def test_prefixes(self):
 | 
					    def test_prefixes(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Test that the prefix values are as expected.
 | 
					        Test that the prefix values are as expected.
 | 
				
			||||||
| 
						 | 
					@ -217,8 +220,7 @@ class BasicTest(BaseTest):
 | 
				
			||||||
    # run the test, the pyvenv.cfg in the venv created in the test will
 | 
					    # run the test, the pyvenv.cfg in the venv created in the test will
 | 
				
			||||||
    # point to the venv being used to run the test, and we lose the link
 | 
					    # point to the venv being used to run the test, and we lose the link
 | 
				
			||||||
    # to the source build - so Python can't initialise properly.
 | 
					    # to the source build - so Python can't initialise properly.
 | 
				
			||||||
    @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate '
 | 
					    @skipInVenv
 | 
				
			||||||
                     'in a venv')
 | 
					 | 
				
			||||||
    def test_executable(self):
 | 
					    def test_executable(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Test that the sys.executable value is as expected.
 | 
					        Test that the sys.executable value is as expected.
 | 
				
			||||||
| 
						 | 
					@ -247,8 +249,50 @@ class BasicTest(BaseTest):
 | 
				
			||||||
        out, err = p.communicate()
 | 
					        out, err = p.communicate()
 | 
				
			||||||
        self.assertEqual(out.strip(), envpy.encode())
 | 
					        self.assertEqual(out.strip(), envpy.encode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@skipInVenv
 | 
				
			||||||
 | 
					class EnsurePipTest(BaseTest):
 | 
				
			||||||
 | 
					    """Test venv module installation of pip."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_no_pip_by_default(self):
 | 
				
			||||||
 | 
					        shutil.rmtree(self.env_dir)
 | 
				
			||||||
 | 
					        self.run_with_capture(venv.create, self.env_dir)
 | 
				
			||||||
 | 
					        envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
 | 
				
			||||||
 | 
					        try_import = 'try:\n import pip\nexcept ImportError:\n print("OK")'
 | 
				
			||||||
 | 
					        cmd = [envpy, '-c', try_import]
 | 
				
			||||||
 | 
					        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
 | 
				
			||||||
 | 
					                             stderr=subprocess.PIPE)
 | 
				
			||||||
 | 
					        out, err = p.communicate()
 | 
				
			||||||
 | 
					        self.assertEqual(err, b"")
 | 
				
			||||||
 | 
					        self.assertEqual(out.strip(), b"OK")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_explicit_no_pip(self):
 | 
				
			||||||
 | 
					        shutil.rmtree(self.env_dir)
 | 
				
			||||||
 | 
					        self.run_with_capture(venv.create, self.env_dir, with_pip=False)
 | 
				
			||||||
 | 
					        envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
 | 
				
			||||||
 | 
					        try_import = 'try:\n import pip\nexcept ImportError:\n print("OK")'
 | 
				
			||||||
 | 
					        cmd = [envpy, '-c', try_import]
 | 
				
			||||||
 | 
					        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
 | 
				
			||||||
 | 
					                             stderr=subprocess.PIPE)
 | 
				
			||||||
 | 
					        out, err = p.communicate()
 | 
				
			||||||
 | 
					        self.assertEqual(err, b"")
 | 
				
			||||||
 | 
					        self.assertEqual(out.strip(), b"OK")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_with_pip(self):
 | 
				
			||||||
 | 
					        shutil.rmtree(self.env_dir)
 | 
				
			||||||
 | 
					        self.run_with_capture(venv.create, self.env_dir, with_pip=True)
 | 
				
			||||||
 | 
					        envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
 | 
				
			||||||
 | 
					        cmd = [envpy, '-m', 'pip', '--version']
 | 
				
			||||||
 | 
					        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
 | 
				
			||||||
 | 
					                             stderr=subprocess.PIPE)
 | 
				
			||||||
 | 
					        out, err = p.communicate()
 | 
				
			||||||
 | 
					        self.assertEqual(err, b"")
 | 
				
			||||||
 | 
					        self.assertTrue(out.startswith(b"pip"))
 | 
				
			||||||
 | 
					        self.assertIn(self.env_dir.encode(), out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_main():
 | 
					def test_main():
 | 
				
			||||||
    run_unittest(BasicTest)
 | 
					    run_unittest(BasicTest, EnsurePipTest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    test_main()
 | 
					    test_main()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,10 +24,13 @@ optional arguments:
 | 
				
			||||||
                        raised.
 | 
					                        raised.
 | 
				
			||||||
  --upgrade             Upgrade the environment directory to use this version
 | 
					  --upgrade             Upgrade the environment directory to use this version
 | 
				
			||||||
                        of Python, assuming Python has been upgraded in-place.
 | 
					                        of Python, assuming Python has been upgraded in-place.
 | 
				
			||||||
 | 
					  --without-pip         Skips installing or upgrading pip in the virtual
 | 
				
			||||||
 | 
					                        environment (pip is bootstrapped by default)
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import sysconfig
 | 
					import sysconfig
 | 
				
			||||||
import types
 | 
					import types
 | 
				
			||||||
| 
						 | 
					@ -56,14 +59,17 @@ class EnvBuilder:
 | 
				
			||||||
    :param symlinks: If True, attempt to symlink rather than copy files into
 | 
					    :param symlinks: If True, attempt to symlink rather than copy files into
 | 
				
			||||||
                     virtual environment.
 | 
					                     virtual environment.
 | 
				
			||||||
    :param upgrade: If True, upgrade an existing virtual environment.
 | 
					    :param upgrade: If True, upgrade an existing virtual environment.
 | 
				
			||||||
 | 
					    :param with_pip: If True, ensure pip is installed in the virtual
 | 
				
			||||||
 | 
					                     environment
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, system_site_packages=False, clear=False,
 | 
					    def __init__(self, system_site_packages=False, clear=False,
 | 
				
			||||||
                 symlinks=False, upgrade=False):
 | 
					                 symlinks=False, upgrade=False, with_pip=False):
 | 
				
			||||||
        self.system_site_packages = system_site_packages
 | 
					        self.system_site_packages = system_site_packages
 | 
				
			||||||
        self.clear = clear
 | 
					        self.clear = clear
 | 
				
			||||||
        self.symlinks = symlinks
 | 
					        self.symlinks = symlinks
 | 
				
			||||||
        self.upgrade = upgrade
 | 
					        self.upgrade = upgrade
 | 
				
			||||||
 | 
					        self.with_pip = with_pip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create(self, env_dir):
 | 
					    def create(self, env_dir):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					@ -76,6 +82,8 @@ class EnvBuilder:
 | 
				
			||||||
        context = self.ensure_directories(env_dir)
 | 
					        context = self.ensure_directories(env_dir)
 | 
				
			||||||
        self.create_configuration(context)
 | 
					        self.create_configuration(context)
 | 
				
			||||||
        self.setup_python(context)
 | 
					        self.setup_python(context)
 | 
				
			||||||
 | 
					        if self.with_pip:
 | 
				
			||||||
 | 
					            self._setup_pip(context)
 | 
				
			||||||
        if not self.upgrade:
 | 
					        if not self.upgrade:
 | 
				
			||||||
            self.setup_scripts(context)
 | 
					            self.setup_scripts(context)
 | 
				
			||||||
            self.post_setup(context)
 | 
					            self.post_setup(context)
 | 
				
			||||||
| 
						 | 
					@ -224,6 +232,12 @@ class EnvBuilder:
 | 
				
			||||||
                    shutil.copyfile(src, dst)
 | 
					                    shutil.copyfile(src, dst)
 | 
				
			||||||
                    break
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_pip(self, context):
 | 
				
			||||||
 | 
					        """Installs or upgrades pip in a virtual environment"""
 | 
				
			||||||
 | 
					        cmd = [context.env_exe, '-m', 'ensurepip', '--upgrade',
 | 
				
			||||||
 | 
					                                                   '--default-pip']
 | 
				
			||||||
 | 
					        subprocess.check_output(cmd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup_scripts(self, context):
 | 
					    def setup_scripts(self, context):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Set up scripts into the created environment from a directory.
 | 
					        Set up scripts into the created environment from a directory.
 | 
				
			||||||
| 
						 | 
					@ -317,7 +331,8 @@ class EnvBuilder:
 | 
				
			||||||
                    shutil.copymode(srcfile, dstfile)
 | 
					                    shutil.copymode(srcfile, dstfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create(env_dir, system_site_packages=False, clear=False, symlinks=False):
 | 
					def create(env_dir, system_site_packages=False, clear=False,
 | 
				
			||||||
 | 
					                    symlinks=False, with_pip=False):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create a virtual environment in a directory.
 | 
					    Create a virtual environment in a directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -333,9 +348,11 @@ def create(env_dir, system_site_packages=False, clear=False, symlinks=False):
 | 
				
			||||||
                  raised.
 | 
					                  raised.
 | 
				
			||||||
    :param symlinks: If True, attempt to symlink rather than copy files into
 | 
					    :param symlinks: If True, attempt to symlink rather than copy files into
 | 
				
			||||||
                     virtual environment.
 | 
					                     virtual environment.
 | 
				
			||||||
 | 
					    :param with_pip: If True, ensure pip is installed in the virtual
 | 
				
			||||||
 | 
					                     environment
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    builder = EnvBuilder(system_site_packages=system_site_packages,
 | 
					    builder = EnvBuilder(system_site_packages=system_site_packages,
 | 
				
			||||||
                                   clear=clear, symlinks=symlinks)
 | 
					                         clear=clear, symlinks=symlinks, with_pip=with_pip)
 | 
				
			||||||
    builder.create(env_dir)
 | 
					    builder.create(env_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main(args=None):
 | 
					def main(args=None):
 | 
				
			||||||
| 
						 | 
					@ -390,12 +407,19 @@ def main(args=None):
 | 
				
			||||||
                                               'directory to use this version '
 | 
					                                               'directory to use this version '
 | 
				
			||||||
                                               'of Python, assuming Python '
 | 
					                                               'of Python, assuming Python '
 | 
				
			||||||
                                               'has been upgraded in-place.')
 | 
					                                               'has been upgraded in-place.')
 | 
				
			||||||
 | 
					        parser.add_argument('--without-pip', dest='with_pip',
 | 
				
			||||||
 | 
					                            default=True, action='store_false',
 | 
				
			||||||
 | 
					                            help='Skips installing or upgrading pip in the '
 | 
				
			||||||
 | 
					                                 'virtual environment (pip is bootstrapped '
 | 
				
			||||||
 | 
					                                 'by default)')
 | 
				
			||||||
        options = parser.parse_args(args)
 | 
					        options = parser.parse_args(args)
 | 
				
			||||||
        if options.upgrade and options.clear:
 | 
					        if options.upgrade and options.clear:
 | 
				
			||||||
            raise ValueError('you cannot supply --upgrade and --clear together.')
 | 
					            raise ValueError('you cannot supply --upgrade and --clear together.')
 | 
				
			||||||
        builder = EnvBuilder(system_site_packages=options.system_site,
 | 
					        builder = EnvBuilder(system_site_packages=options.system_site,
 | 
				
			||||||
                             clear=options.clear, symlinks=options.symlinks,
 | 
					                             clear=options.clear,
 | 
				
			||||||
                             upgrade=options.upgrade)
 | 
					                             symlinks=options.symlinks,
 | 
				
			||||||
 | 
					                             upgrade=options.upgrade,
 | 
				
			||||||
 | 
					                             with_pip=options.with_pip)
 | 
				
			||||||
        for d in options.dirs:
 | 
					        for d in options.dirs:
 | 
				
			||||||
            builder.create(d)
 | 
					            builder.create(d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,8 @@ Core and Builtins
 | 
				
			||||||
Library
 | 
					Library
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Issue #19552: venv now supports bootstrapping pip into virtual environments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Issue #17134: Finalize interface to Windows' certificate store. Cert and
 | 
					- Issue #17134: Finalize interface to Windows' certificate store. Cert and
 | 
				
			||||||
  CRL enumeration are now two functions. enum_certificates() also returns
 | 
					  CRL enumeration are now two functions. enum_certificates() also returns
 | 
				
			||||||
  purpose flags as set of OIDs.
 | 
					  purpose flags as set of OIDs.
 | 
				
			||||||
| 
						 | 
					@ -378,6 +380,9 @@ Build
 | 
				
			||||||
Tools/Demos
 | 
					Tools/Demos
 | 
				
			||||||
-----------
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Issue #19552: pyvenv now bootstraps pip into virtual environments by
 | 
				
			||||||
 | 
					  default (pass --without-pip to request the old behaviour)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Issue #19390: Argument Clinic no longer accepts malformed Python
 | 
					- Issue #19390: Argument Clinic no longer accepts malformed Python
 | 
				
			||||||
  and C ids.
 | 
					  and C ids.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue