Updates vendored setuptools to 44.1.1

This commit is contained in:
Labrys of Knossos 2022-11-28 22:11:52 -05:00
commit d8da02cb69
55 changed files with 2910 additions and 1457 deletions

View file

@ -2,8 +2,7 @@ __all__ = [
'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop',
'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts',
'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts',
'register', 'bdist_wininst', 'upload_docs', 'upload', 'build_clib',
'dist_info',
'bdist_wininst', 'upload_docs', 'build_clib', 'dist_info',
]
from distutils.command.bdist import bdist

View file

@ -284,7 +284,7 @@ class bdist_egg(Command):
"or refer to a module" % (ep,)
)
pyver = sys.version[:3]
pyver = '{}.{}'.format(*sys.version_info)
pkg = ep.module_name
full = '.'.join(ep.attrs)
base = ep.attrs[0]

View file

@ -1,7 +1,6 @@
import os
import sys
import itertools
import imp
from distutils.command.build_ext import build_ext as _du_build_ext
from distutils.file_util import copy_file
from distutils.ccompiler import new_compiler
@ -12,6 +11,13 @@ from distutils import log
from setuptools.extension import Library
from setuptools.extern import six
if six.PY2:
import imp
EXTENSION_SUFFIXES = [s for s, _, tp in imp.get_suffixes() if tp == imp.C_EXTENSION]
else:
from importlib.machinery import EXTENSION_SUFFIXES
try:
# Attempt to use Cython for building extensions, if available
from Cython.Distutils.build_ext import build_ext as _build_ext
@ -64,7 +70,7 @@ if_dl = lambda s: s if have_rtld else ''
def get_abi3_suffix():
"""Return the file extension for an abi3-compliant Extension()"""
for suffix, _, _ in (s for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION):
for suffix in EXTENSION_SUFFIXES:
if '.abi3' in suffix: # Unix
return suffix
elif suffix == '.pyd': # Windows
@ -107,7 +113,7 @@ class build_ext(_build_ext):
if fullname in self.ext_map:
ext = self.ext_map[fullname]
use_abi3 = (
six.PY3
not six.PY2
and getattr(ext, 'py_limited_api')
and get_abi3_suffix()
)

View file

@ -7,7 +7,7 @@ import io
from setuptools.extern import six
from pkg_resources import Distribution, PathMetadata, normalize_path
import pkg_resources
from setuptools.command.easy_install import easy_install
from setuptools import namespaces
import setuptools
@ -65,9 +65,9 @@ class develop(namespaces.DevelopInstaller, easy_install):
if self.egg_path is None:
self.egg_path = os.path.abspath(ei.egg_base)
target = normalize_path(self.egg_base)
egg_path = normalize_path(os.path.join(self.install_dir,
self.egg_path))
target = pkg_resources.normalize_path(self.egg_base)
egg_path = pkg_resources.normalize_path(
os.path.join(self.install_dir, self.egg_path))
if egg_path != target:
raise DistutilsOptionError(
"--egg-path must be a relative path from the install"
@ -75,9 +75,9 @@ class develop(namespaces.DevelopInstaller, easy_install):
)
# Make a distribution for the package's source
self.dist = Distribution(
self.dist = pkg_resources.Distribution(
target,
PathMetadata(target, os.path.abspath(ei.egg_info)),
pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)),
project_name=ei.egg_name
)
@ -97,24 +97,25 @@ class develop(namespaces.DevelopInstaller, easy_install):
path_to_setup = egg_base.replace(os.sep, '/').rstrip('/')
if path_to_setup != os.curdir:
path_to_setup = '../' * (path_to_setup.count('/') + 1)
resolved = normalize_path(
resolved = pkg_resources.normalize_path(
os.path.join(install_dir, egg_path, path_to_setup)
)
if resolved != normalize_path(os.curdir):
if resolved != pkg_resources.normalize_path(os.curdir):
raise DistutilsOptionError(
"Can't get a consistent path to setup script from"
" installation directory", resolved, normalize_path(os.curdir))
" installation directory", resolved,
pkg_resources.normalize_path(os.curdir))
return path_to_setup
def install_for_development(self):
if six.PY3 and getattr(self.distribution, 'use_2to3', False):
if not six.PY2 and getattr(self.distribution, 'use_2to3', False):
# If we run 2to3 we can not do this inplace:
# Ensure metadata is up-to-date
self.reinitialize_command('build_py', inplace=0)
self.run_command('build_py')
bpy_cmd = self.get_finalized_command("build_py")
build_path = normalize_path(bpy_cmd.build_lib)
build_path = pkg_resources.normalize_path(bpy_cmd.build_lib)
# Build extensions
self.reinitialize_command('egg_info', egg_base=build_path)
@ -128,7 +129,8 @@ class develop(namespaces.DevelopInstaller, easy_install):
self.egg_path = build_path
self.dist.location = build_path
# XXX
self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info)
self.dist._provider = pkg_resources.PathMetadata(
build_path, ei_cmd.egg_info)
else:
# Without 2to3 inplace works fine:
self.run_command('egg_info')
@ -200,6 +202,7 @@ class VersionlessRequirement:
name as the 'requirement' so that scripts will work across
multiple versions.
>>> from pkg_resources import Distribution
>>> dist = Distribution(project_name='foo', version='1.0')
>>> str(dist.as_requirement())
'foo==1.0'

View file

@ -241,7 +241,7 @@ class easy_install(Command):
"""
Render the Setuptools version and installation details, then exit.
"""
ver = sys.version[:3]
ver = '{}.{}'.format(*sys.version_info)
dist = get_distribution('setuptools')
tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})'
print(tmpl.format(**locals()))
@ -410,7 +410,13 @@ class easy_install(Command):
]
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:
log.set_verbosity(self.verbose)
try:
@ -1180,8 +1186,7 @@ class easy_install(Command):
# to the setup.cfg file.
ei_opts = self.distribution.get_option_dict('easy_install').copy()
fetch_directives = (
'find_links', 'site_dirs', 'index_url', 'optimize',
'site_dirs', 'allow_hosts',
'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts',
)
fetch_options = {}
for key, val in ei_opts.items():
@ -1412,7 +1417,7 @@ def get_site_dirs():
os.path.join(
prefix,
"lib",
"python" + sys.version[:3],
"python{}.{}".format(*sys.version_info),
"site-packages",
),
os.path.join(prefix, "lib", "site-python"),
@ -1433,7 +1438,7 @@ def get_site_dirs():
home,
'Library',
'Python',
sys.version[:3],
'{}.{}'.format(*sys.version_info),
'site-packages',
)
sitedirs.append(home_sp)
@ -1562,7 +1567,7 @@ def get_exe_prefixes(exe_filename):
continue
if parts[0].upper() in ('PURELIB', 'PLATLIB'):
contents = z.read(name)
if six.PY3:
if not six.PY2:
contents = contents.decode()
for pth in yield_lines(contents):
pth = pth.strip().replace('\\', '/')

View file

@ -266,7 +266,7 @@ class egg_info(InfoCommon, Command):
to the file.
"""
log.info("writing %s to %s", what, filename)
if six.PY3:
if not six.PY2:
data = data.encode("utf-8")
if not self.dry_run:
f = open(filename, 'wb')
@ -568,6 +568,7 @@ class manifest_maker(sdist):
def add_defaults(self):
sdist.add_defaults(self)
self.check_license()
self.filelist.append(self.template)
self.filelist.append(self.manifest)
rcfiles = list(walk_revctrl())

View file

@ -114,7 +114,7 @@ class install(orig.install):
args.insert(0, setuptools.bootstrap_install_from)
cmd.args = args
cmd.run()
cmd.run(show_deprecation=False)
setuptools.bootstrap_install_from = None

View file

@ -1,5 +1,5 @@
import os
import imp
import sys
from itertools import product, starmap
import distutils.command.install_lib as orig
@ -74,10 +74,10 @@ class install_lib(orig.install_lib):
yield '__init__.pyc'
yield '__init__.pyo'
if not hasattr(imp, 'get_tag'):
if not hasattr(sys, 'implementation'):
return
base = os.path.join('__pycache__', '__init__.' + imp.get_tag())
base = os.path.join('__pycache__', '__init__.' + sys.implementation.cache_tag)
yield base + '.pyc'
yield base + '.pyo'
yield base + '.opt-1.pyc'

View file

@ -1,18 +1,18 @@
from distutils import log
import distutils.command.register as orig
from setuptools.errors import RemovedCommandError
class register(orig.register):
__doc__ = orig.register.__doc__
"""Formerly used to register packages on PyPI."""
def run(self):
try:
# Make sure that we are using valid current name/version info
self.run_command('egg_info')
orig.register.run(self)
finally:
self.announce(
"WARNING: Registering is deprecated, use twine to "
"upload instead (https://pypi.org/p/twine/)",
log.WARN
)
msg = (
"The register command has been removed, use twine to upload "
+ "instead (https://pypi.org/p/twine)"
)
self.announce("ERROR: " + msg, log.ERROR)
raise RemovedCommandError(msg)

View file

@ -5,7 +5,7 @@ import sys
import io
import contextlib
from setuptools.extern import six
from setuptools.extern import six, ordered_set
from .py36compat import sdist_add_defaults
@ -121,19 +121,40 @@ class sdist(sdist_add_defaults, orig.sdist):
if has_leaky_handle:
read_template = __read_template_hack
def _add_defaults_optional(self):
if six.PY2:
sdist_add_defaults._add_defaults_optional(self)
else:
super()._add_defaults_optional()
if os.path.isfile('pyproject.toml'):
self.filelist.append('pyproject.toml')
def _add_defaults_python(self):
"""getting python files"""
if self.distribution.has_pure_modules():
build_py = self.get_finalized_command('build_py')
self.filelist.extend(build_py.get_source_files())
# This functionality is incompatible with include_package_data, and
# will in fact create an infinite recursion if include_package_data
# is True. Use of include_package_data will imply that
# distutils-style automatic handling of package_data is disabled
if not self.distribution.include_package_data:
for _, src_dir, _, filenames in build_py.data_files:
self.filelist.extend([os.path.join(src_dir, filename)
for filename in filenames])
self._add_data_files(self._safe_data_files(build_py))
def _safe_data_files(self, build_py):
"""
Extracting data_files from build_py is known to cause
infinite recursion errors when `include_package_data`
is enabled, so suppress it in that case.
"""
if self.distribution.include_package_data:
return ()
return build_py.data_files
def _add_data_files(self, data_files):
"""
Add data files as found in build_py.data_files.
"""
self.filelist.extend(
os.path.join(src_dir, name)
for _, src_dir, _, filenames in data_files
for name in filenames
)
def _add_defaults_data_files(self):
try:
@ -186,7 +207,7 @@ class sdist(sdist_add_defaults, orig.sdist):
manifest = open(self.manifest, 'rb')
for line in manifest:
# The manifest must contain UTF-8. See #303.
if six.PY3:
if not six.PY2:
try:
line = line.decode('UTF-8')
except UnicodeDecodeError:
@ -198,3 +219,34 @@ class sdist(sdist_add_defaults, orig.sdist):
continue
self.filelist.append(line)
manifest.close()
def check_license(self):
"""Checks if license_file' or 'license_files' is configured and adds any
valid paths to 'self.filelist'.
"""
files = ordered_set.OrderedSet()
opts = self.distribution.get_option_dict('metadata')
# ignore the source of the value
_, license_file = opts.get('license_file', (None, None))
if license_file is None:
log.debug("'license_file' option was not specified")
else:
files.add(license_file)
try:
files.update(self.distribution.metadata.license_files)
except TypeError:
log.warn("warning: 'license_files' option is malformed")
for f in files:
if not os.path.exists(f):
log.warn(
"warning: Failed to find the configured license file '%s'",
f)
files.remove(f)
self.filelist.extend(files)

View file

@ -15,6 +15,7 @@ from pkg_resources import (resource_listdir, resource_exists, normalize_path,
working_set, _namespace_packages, evaluate_marker,
add_activation_listener, require, EntryPoint)
from setuptools import Command
from .build_py import _unique_everseen
__metaclass__ = type
@ -73,7 +74,7 @@ class NonDataProperty:
class test(Command):
"""Command to run unit tests after in-place build"""
description = "run unit tests after in-place build"
description = "run unit tests after in-place build (deprecated)"
user_options = [
('test-module=', 'm', "Run 'test_suite' in specified module"),
@ -128,7 +129,7 @@ class test(Command):
@contextlib.contextmanager
def project_on_sys_path(self, include_dists=[]):
with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
with_2to3 = not six.PY2 and getattr(self.distribution, 'use_2to3', False)
if with_2to3:
# If we run 2to3 we can not do this inplace:
@ -186,7 +187,7 @@ class test(Command):
orig_pythonpath = os.environ.get('PYTHONPATH', nothing)
current_pythonpath = os.environ.get('PYTHONPATH', '')
try:
prefix = os.pathsep.join(paths)
prefix = os.pathsep.join(_unique_everseen(paths))
to_join = filter(None, [prefix, current_pythonpath])
new_path = os.pathsep.join(to_join)
if new_path:
@ -213,6 +214,14 @@ class test(Command):
return itertools.chain(ir_d, tr_d, er_d)
def run(self):
self.announce(
"WARNING: Testing via this command is deprecated and will be "
"removed in a future version. Users looking for a generic test "
"entry point independent of test runner are encouraged to use "
"tox.",
log.WARN,
)
installed_dists = self.install_dists(self.distribution)
cmd = ' '.join(self._argv)
@ -231,7 +240,7 @@ class test(Command):
# Purge modules under test from sys.modules. The test loader will
# re-import them from the build location. Required when 2to3 is used
# with namespace packages.
if six.PY3 and getattr(self.distribution, 'use_2to3', False):
if not six.PY2 and getattr(self.distribution, 'use_2to3', False):
module = self.test_suite.split('.')[0]
if module in _namespace_packages:
del_modules = []

View file

@ -1,196 +1,17 @@
import io
import os
import hashlib
import getpass
import platform
from base64 import standard_b64encode
from distutils import log
from distutils.command import upload as orig
from distutils.spawn import spawn
from distutils.errors import DistutilsError
from setuptools.errors import RemovedCommandError
from setuptools.extern.six.moves.urllib.request import urlopen, Request
from setuptools.extern.six.moves.urllib.error import HTTPError
from setuptools.extern.six.moves.urllib.parse import urlparse
class upload(orig.upload):
"""
Override default upload behavior to obtain password
in a variety of different ways.
"""
"""Formerly used to upload packages to PyPI."""
def run(self):
try:
orig.upload.run(self)
finally:
self.announce(
"WARNING: Uploading via this command is deprecated, use twine "
"to upload instead (https://pypi.org/p/twine/)",
log.WARN
)
def finalize_options(self):
orig.upload.finalize_options(self)
self.username = (
self.username or
getpass.getuser()
)
# Attempt to obtain password. Short circuit evaluation at the first
# sign of success.
self.password = (
self.password or
self._load_password_from_keyring() or
self._prompt_for_password()
msg = (
"The upload command has been removed, use twine to upload "
+ "instead (https://pypi.org/p/twine)"
)
def upload_file(self, command, pyversion, filename):
# Makes sure the repository URL is compliant
schema, netloc, url, params, query, fragments = \
urlparse(self.repository)
if params or query or fragments:
raise AssertionError("Incompatible url %s" % self.repository)
if schema not in ('http', 'https'):
raise AssertionError("unsupported schema " + schema)
# Sign if requested
if self.sign:
gpg_args = ["gpg", "--detach-sign", "-a", filename]
if self.identity:
gpg_args[2:2] = ["--local-user", self.identity]
spawn(gpg_args,
dry_run=self.dry_run)
# Fill in the data - send all the meta-data in case we need to
# register a new release
with open(filename, 'rb') as f:
content = f.read()
meta = self.distribution.metadata
data = {
# action
':action': 'file_upload',
'protocol_version': '1',
# identify release
'name': meta.get_name(),
'version': meta.get_version(),
# file content
'content': (os.path.basename(filename),content),
'filetype': command,
'pyversion': pyversion,
'md5_digest': hashlib.md5(content).hexdigest(),
# additional meta-data
'metadata_version': str(meta.get_metadata_version()),
'summary': meta.get_description(),
'home_page': meta.get_url(),
'author': meta.get_contact(),
'author_email': meta.get_contact_email(),
'license': meta.get_licence(),
'description': meta.get_long_description(),
'keywords': meta.get_keywords(),
'platform': meta.get_platforms(),
'classifiers': meta.get_classifiers(),
'download_url': meta.get_download_url(),
# PEP 314
'provides': meta.get_provides(),
'requires': meta.get_requires(),
'obsoletes': meta.get_obsoletes(),
}
data['comment'] = ''
if self.sign:
data['gpg_signature'] = (os.path.basename(filename) + ".asc",
open(filename+".asc", "rb").read())
# set up the authentication
user_pass = (self.username + ":" + self.password).encode('ascii')
# The exact encoding of the authentication string is debated.
# Anyway PyPI only accepts ascii for both username or password.
auth = "Basic " + standard_b64encode(user_pass).decode('ascii')
# Build up the MIME payload for the POST data
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
sep_boundary = b'\r\n--' + boundary.encode('ascii')
end_boundary = sep_boundary + b'--\r\n'
body = io.BytesIO()
for key, value in data.items():
title = '\r\nContent-Disposition: form-data; name="%s"' % key
# handle multiple entries for the same name
if not isinstance(value, list):
value = [value]
for value in value:
if type(value) is tuple:
title += '; filename="%s"' % value[0]
value = value[1]
else:
value = str(value).encode('utf-8')
body.write(sep_boundary)
body.write(title.encode('utf-8'))
body.write(b"\r\n\r\n")
body.write(value)
body.write(end_boundary)
body = body.getvalue()
msg = "Submitting %s to %s" % (filename, self.repository)
self.announce(msg, log.INFO)
# build the Request
headers = {
'Content-type': 'multipart/form-data; boundary=%s' % boundary,
'Content-length': str(len(body)),
'Authorization': auth,
}
request = Request(self.repository, data=body,
headers=headers)
# send the data
try:
result = urlopen(request)
status = result.getcode()
reason = result.msg
except HTTPError as e:
status = e.code
reason = e.msg
except OSError as e:
self.announce(str(e), log.ERROR)
raise
if status == 200:
self.announce('Server response (%s): %s' % (status, reason),
log.INFO)
if self.show_response:
text = getattr(self, '_read_pypi_response',
lambda x: None)(result)
if text is not None:
msg = '\n'.join(('-' * 75, text, '-' * 75))
self.announce(msg, log.INFO)
else:
msg = 'Upload failed (%s): %s' % (status, reason)
self.announce(msg, log.ERROR)
raise DistutilsError(msg)
def _load_password_from_keyring(self):
"""
Attempt to load password from keyring. Suppress Exceptions.
"""
try:
keyring = __import__('keyring')
return keyring.get_password(self.repository, self.username)
except Exception:
pass
def _prompt_for_password(self):
"""
Prompt for a password on the tty. Suppress Exceptions.
"""
try:
return getpass.getpass()
except (Exception, KeyboardInterrupt):
pass
self.announce("ERROR: " + msg, log.ERROR)
raise RemovedCommandError(msg)

View file

@ -24,7 +24,7 @@ from .upload import upload
def _encode(s):
errors = 'surrogateescape' if six.PY3 else 'strict'
errors = 'strict' if six.PY2 else 'surrogateescape'
return s.encode('utf-8', errors)
@ -153,7 +153,7 @@ class upload_docs(upload):
# set up the authentication
credentials = _encode(self.username + ':' + self.password)
credentials = standard_b64encode(credentials)
if six.PY3:
if not six.PY2:
credentials = credentials.decode('ascii')
auth = "Basic " + credentials