aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools/command
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/command')
-rw-r--r--setuptools/command/__init__.py3
-rw-r--r--[-rwxr-xr-x]setuptools/command/alias.py0
-rw-r--r--setuptools/command/bdist_egg.py28
-rw-r--r--[-rwxr-xr-x]setuptools/command/bdist_rpm.py0
-rw-r--r--[-rwxr-xr-x]setuptools/command/bdist_wininst.py0
-rw-r--r--setuptools/command/build_ext.py15
-rw-r--r--[-rwxr-xr-x]setuptools/command/develop.py31
-rw-r--r--setuptools/command/dist_info.py8
-rw-r--r--[-rwxr-xr-x]setuptools/command/easy_install.py89
-rw-r--r--[-rwxr-xr-x]setuptools/command/egg_info.py87
-rw-r--r--[-rwxr-xr-x]setuptools/command/install_egg_info.py0
-rw-r--r--[-rwxr-xr-x]setuptools/command/install_scripts.py0
-rw-r--r--[-rwxr-xr-x]setuptools/command/register.py14
-rw-r--r--[-rwxr-xr-x]setuptools/command/rotate.py0
-rw-r--r--[-rwxr-xr-x]setuptools/command/saveopts.py0
-rw-r--r--[-rwxr-xr-x]setuptools/command/sdist.py7
-rw-r--r--[-rwxr-xr-x]setuptools/command/setopt.py0
-rw-r--r--setuptools/command/test.py22
-rw-r--r--setuptools/command/upload.py154
19 files changed, 350 insertions, 108 deletions
diff --git a/setuptools/command/__init__.py b/setuptools/command/__init__.py
index 4fe3bb56..fe619e2e 100644
--- a/setuptools/command/__init__.py
+++ b/setuptools/command/__init__.py
@@ -2,7 +2,8 @@ __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',
+ 'register', 'bdist_wininst', 'upload_docs', 'upload', 'build_clib',
+ 'dist_info',
]
from distutils.command.bdist import bdist
diff --git a/setuptools/command/alias.py b/setuptools/command/alias.py
index 4532b1cc..4532b1cc 100755..100644
--- a/setuptools/command/alias.py
+++ b/setuptools/command/alias.py
diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py
index 51755d52..9f8df917 100644
--- a/setuptools/command/bdist_egg.py
+++ b/setuptools/command/bdist_egg.py
@@ -8,6 +8,7 @@ from distutils import log
from types import CodeType
import sys
import os
+import re
import textwrap
import marshal
@@ -38,6 +39,7 @@ def strip_module(filename):
filename = filename[:-6]
return filename
+
def sorted_walk(dir):
"""Do os.walk in a reproducible way,
independent of indeterministic filesystem readdir order
@@ -47,6 +49,7 @@ def sorted_walk(dir):
files.sort()
yield base, dirs, files
+
def write_stub(resource, pyfile):
_stub_template = textwrap.dedent("""
def __bootstrap__():
@@ -240,11 +243,28 @@ class bdist_egg(Command):
log.info("Removing .py files from temporary directory")
for base, dirs, files in walk_egg(self.bdist_dir):
for name in files:
+ path = os.path.join(base, name)
+
if name.endswith('.py'):
- path = os.path.join(base, name)
log.debug("Deleting %s", path)
os.unlink(path)
+ if base.endswith('__pycache__'):
+ path_old = path
+
+ pattern = r'(?P<name>.+)\.(?P<magic>[^.]+)\.pyc'
+ m = re.match(pattern, name)
+ path_new = os.path.join(
+ base, os.pardir, m.group('name') + '.pyc')
+ log.info(
+ "Renaming file from [%s] to [%s]"
+ % (path_old, path_new))
+ try:
+ os.remove(path_new)
+ except OSError:
+ pass
+ os.rename(path_old, path_new)
+
def zip_safe(self):
safe = getattr(self.distribution, 'zip_safe', None)
if safe is not None:
@@ -391,10 +411,12 @@ def scan_module(egg_dir, base, name, stubs):
return True # Extension module
pkg = base[len(egg_dir) + 1:].replace(os.sep, '.')
module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
- if sys.version_info < (3, 3):
+ if six.PY2:
skip = 8 # skip magic & date
- else:
+ elif sys.version_info < (3, 7):
skip = 12 # skip magic & date & file size
+ else:
+ skip = 16 # skip magic & reserved? & date & file size
f = open(filename, 'rb')
f.read(skip)
code = marshal.load(f)
diff --git a/setuptools/command/bdist_rpm.py b/setuptools/command/bdist_rpm.py
index 70730927..70730927 100755..100644
--- a/setuptools/command/bdist_rpm.py
+++ b/setuptools/command/bdist_rpm.py
diff --git a/setuptools/command/bdist_wininst.py b/setuptools/command/bdist_wininst.py
index 073de97b..073de97b 100755..100644
--- a/setuptools/command/bdist_wininst.py
+++ b/setuptools/command/bdist_wininst.py
diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py
index 36f53f0d..60a8a32f 100644
--- a/setuptools/command/build_ext.py
+++ b/setuptools/command/build_ext.py
@@ -15,6 +15,9 @@ from setuptools.extern import six
try:
# Attempt to use Cython for building extensions, if available
from Cython.Distutils.build_ext import build_ext as _build_ext
+ # Additionally, assert that the compiler module will load
+ # also. Ref #1229.
+ __import__('Cython.Compiler.Main')
except ImportError:
_build_ext = _du_build_ext
@@ -109,7 +112,7 @@ class build_ext(_build_ext):
and get_abi3_suffix()
)
if use_abi3:
- so_ext = _get_config_var_837('EXT_SUFFIX')
+ so_ext = get_config_var('EXT_SUFFIX')
filename = filename[:-len(so_ext)]
filename = filename + get_abi3_suffix()
if isinstance(ext, Library):
@@ -316,13 +319,3 @@ else:
self.create_static_lib(
objects, basename, output_dir, debug, target_lang
)
-
-
-def _get_config_var_837(name):
- """
- In https://github.com/pypa/setuptools/pull/837, we discovered
- Python 3.3.0 exposes the extension suffix under the name 'SO'.
- """
- if sys.version_info < (3, 3, 1):
- name = 'SO'
- return get_config_var(name)
diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py
index 85b23c60..009e4f93 100755..100644
--- a/setuptools/command/develop.py
+++ b/setuptools/command/develop.py
@@ -7,11 +7,13 @@ 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
+__metaclass__ = type
+
class develop(namespaces.DevelopInstaller, easy_install):
"""Set up package for development"""
@@ -63,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"
@@ -73,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
)
@@ -95,11 +97,14 @@ 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(os.path.join(install_dir, egg_path, path_to_setup))
- if resolved != normalize_path(os.curdir):
+ resolved = pkg_resources.normalize_path(
+ os.path.join(install_dir, egg_path, path_to_setup)
+ )
+ 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):
@@ -110,7 +115,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
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)
@@ -124,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')
@@ -190,12 +196,13 @@ class develop(namespaces.DevelopInstaller, easy_install):
return easy_install.install_wrapper_scripts(self, dist)
-class VersionlessRequirement(object):
+class VersionlessRequirement:
"""
Adapt a pkg_resources.Distribution to simply return the project
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'
diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py
index c6c6dacb..c45258fa 100644
--- a/setuptools/command/dist_info.py
+++ b/setuptools/command/dist_info.py
@@ -4,7 +4,6 @@ As defined in the wheel specification
"""
import os
-import shutil
from distutils.core import Command
from distutils import log
@@ -27,14 +26,11 @@ class dist_info(Command):
def run(self):
egg_info = self.get_finalized_command('egg_info')
+ egg_info.egg_base = self.egg_base
+ egg_info.finalize_options()
egg_info.run()
dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info'
log.info("creating '{}'".format(os.path.abspath(dist_info_dir)))
bdist_wheel = self.get_finalized_command('bdist_wheel')
bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir)
-
- if self.egg_base:
- destination = os.path.join(self.egg_base, dist_info_dir)
- log.info("creating '{}'".format(os.path.abspath(destination)))
- shutil.move(dist_info_dir, destination)
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 8fba7b41..06c98271 100755..100644
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -40,12 +40,16 @@ import subprocess
import shlex
import io
+
+from sysconfig import get_config_vars, get_path
+
+from setuptools import SetuptoolsDeprecationWarning
+
from setuptools.extern import six
from setuptools.extern.six.moves import configparser, map
from setuptools import Command
from setuptools.sandbox import run_setup
-from setuptools.py31compat import get_path, get_config_vars
from setuptools.py27compat import rmtree_safe
from setuptools.command import setopt
from setuptools.archive_util import unpack_archive
@@ -53,6 +57,7 @@ from setuptools.package_index import (
PackageIndex, parse_requirement_arg, URL_SCHEME,
)
from setuptools.command import bdist_egg, egg_info
+from setuptools.wheel import Wheel
from pkg_resources import (
yield_lines, normalize_path, resource_string, ensure_directory,
get_distribution, find_distributions, Environment, Requirement,
@@ -61,6 +66,8 @@ from pkg_resources import (
)
import pkg_resources.py31compat
+__metaclass__ = type
+
# Turn on PEP440Warnings
warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
@@ -92,7 +99,7 @@ def samefile(p1, p2):
if six.PY2:
- def _to_ascii(s):
+ def _to_bytes(s):
return s
def isascii(s):
@@ -103,8 +110,8 @@ if six.PY2:
return False
else:
- def _to_ascii(s):
- return s.encode('ascii')
+ def _to_bytes(s):
+ return s.encode('utf8')
def isascii(s):
try:
@@ -318,7 +325,7 @@ class easy_install(Command):
self.all_site_dirs.append(normalize_path(d))
if not self.editable:
self.check_site_dir()
- self.index_url = self.index_url or "https://pypi.python.org/simple"
+ self.index_url = self.index_url or "https://pypi.org/simple/"
self.shadow_path = self.all_site_dirs[:]
for path_item in self.install_dir, normalize_path(self.script_dir):
if path_item not in self.shadow_path:
@@ -628,7 +635,7 @@ class easy_install(Command):
@contextlib.contextmanager
def _tmpdir(self):
- tmpdir = tempfile.mkdtemp(prefix=six.u("easy_install-"))
+ tmpdir = tempfile.mkdtemp(prefix=u"easy_install-")
try:
# cast to str as workaround for #709 and #710 and #712
yield str(tmpdir)
@@ -801,7 +808,7 @@ class easy_install(Command):
if is_script:
body = self._load_template(dev_path) % locals()
script_text = ScriptWriter.get_header(script_text) + body
- self.write_script(script_name, _to_ascii(script_text), 'b')
+ self.write_script(script_name, _to_bytes(script_text), 'b')
@staticmethod
def _load_template(dev_path):
@@ -827,14 +834,16 @@ class easy_install(Command):
target = os.path.join(self.script_dir, script_name)
self.add_output(target)
+ if self.dry_run:
+ return
+
mask = current_umask()
- if not self.dry_run:
- ensure_directory(target)
- if os.path.exists(target):
- os.unlink(target)
- with open(target, "w" + mode) as f:
- f.write(contents)
- chmod(target, 0o777 - mask)
+ ensure_directory(target)
+ if os.path.exists(target):
+ os.unlink(target)
+ with open(target, "w" + mode) as f:
+ f.write(contents)
+ chmod(target, 0o777 - mask)
def install_eggs(self, spec, dist_filename, tmpdir):
# .egg dirs or files are already built, so just return them
@@ -842,6 +851,8 @@ class easy_install(Command):
return [self.install_egg(dist_filename, tmpdir)]
elif dist_filename.lower().endswith('.exe'):
return [self.install_exe(dist_filename, tmpdir)]
+ elif dist_filename.lower().endswith('.whl'):
+ return [self.install_wheel(dist_filename, tmpdir)]
# Anything else, try to extract and build
setup_base = tmpdir
@@ -1038,6 +1049,35 @@ class easy_install(Command):
f.write('\n'.join(locals()[name]) + '\n')
f.close()
+ def install_wheel(self, wheel_path, tmpdir):
+ wheel = Wheel(wheel_path)
+ assert wheel.is_compatible()
+ destination = os.path.join(self.install_dir, wheel.egg_name())
+ destination = os.path.abspath(destination)
+ if not self.dry_run:
+ ensure_directory(destination)
+ if os.path.isdir(destination) and not os.path.islink(destination):
+ dir_util.remove_tree(destination, dry_run=self.dry_run)
+ elif os.path.exists(destination):
+ self.execute(
+ os.unlink,
+ (destination,),
+ "Removing " + destination,
+ )
+ try:
+ self.execute(
+ wheel.install_as_egg,
+ (destination,),
+ ("Installing %s to %s") % (
+ os.path.basename(wheel_path),
+ os.path.dirname(destination)
+ ),
+ )
+ finally:
+ update_dist_caches(destination, fix_zipimporter_caches=False)
+ self.add_output(destination)
+ return self.egg_distribution(destination)
+
__mv_warning = textwrap.dedent("""
Because this distribution was installed --multi-version, before you can
import modules from this package in an application, you will need to
@@ -1216,7 +1256,6 @@ class easy_install(Command):
def byte_compile(self, to_compile):
if sys.dont_write_bytecode:
- self.warn('byte-compiling is disabled, skipping.')
return
from distutils.util import byte_compile
@@ -1817,7 +1856,7 @@ def _update_zipimporter_cache(normalized_path, cache, updater=None):
# get/del patterns instead. For more detailed information see the
# following links:
# https://github.com/pypa/setuptools/issues/202#issuecomment-202913420
- # https://bitbucket.org/pypy/pypy/src/dd07756a34a41f674c0cacfbc8ae1d4cc9ea2ae4/pypy/module/zipimport/interp_zipimport.py#cl-99
+ # http://bit.ly/2h9itJX
old_entry = cache[p]
del cache[p]
new_entry = updater and updater(p, old_entry)
@@ -2016,7 +2055,7 @@ class WindowsCommandSpec(CommandSpec):
split_args = dict(posix=False)
-class ScriptWriter(object):
+class ScriptWriter:
"""
Encapsulates behavior around writing entry point scripts for console and
gui apps.
@@ -2041,7 +2080,7 @@ class ScriptWriter(object):
@classmethod
def get_script_args(cls, dist, executable=None, wininst=False):
# for backward compatibility
- warnings.warn("Use get_args", DeprecationWarning)
+ warnings.warn("Use get_args", EasyInstallDeprecationWarning)
writer = (WindowsScriptWriter if wininst else ScriptWriter).best()
header = cls.get_script_header("", executable, wininst)
return writer.get_args(dist, header)
@@ -2049,12 +2088,10 @@ class ScriptWriter(object):
@classmethod
def get_script_header(cls, script_text, executable=None, wininst=False):
# for backward compatibility
- warnings.warn("Use get_header", DeprecationWarning)
+ warnings.warn("Use get_header", EasyInstallDeprecationWarning, stacklevel=2)
if wininst:
executable = "python.exe"
- cmd = cls.command_spec_class.best().from_param(executable)
- cmd.install_options(script_text)
- return cmd.as_header()
+ return cls.get_header(script_text, executable)
@classmethod
def get_args(cls, dist, header=None):
@@ -2086,7 +2123,7 @@ class ScriptWriter(object):
@classmethod
def get_writer(cls, force_windows):
# for backward compatibility
- warnings.warn("Use best", DeprecationWarning)
+ warnings.warn("Use best", EasyInstallDeprecationWarning)
return WindowsScriptWriter.best() if force_windows else cls.best()
@classmethod
@@ -2118,7 +2155,7 @@ class WindowsScriptWriter(ScriptWriter):
@classmethod
def get_writer(cls):
# for backward compatibility
- warnings.warn("Use best", DeprecationWarning)
+ warnings.warn("Use best", EasyInstallDeprecationWarning)
return cls.best()
@classmethod
@@ -2299,3 +2336,7 @@ def _patch_usage():
yield
finally:
distutils.core.gen_usage = saved
+
+class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
+ """Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning."""
+
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index a183d15d..d9fe3da3 100755..100644
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -30,8 +30,8 @@ from pkg_resources import (
import setuptools.unicode_utils as unicode_utils
from setuptools.glob import glob
-from pkg_resources.extern import packaging
-
+from setuptools.extern import packaging
+from setuptools import SetuptoolsDeprecationWarning
def translate_pattern(glob):
"""
@@ -116,7 +116,33 @@ def translate_pattern(glob):
return re.compile(pat, flags=re.MULTILINE|re.DOTALL)
-class egg_info(Command):
+class InfoCommon:
+ tag_build = None
+ tag_date = None
+
+ @property
+ def name(self):
+ return safe_name(self.distribution.get_name())
+
+ def tagged_version(self):
+ version = self.distribution.get_version()
+ # egg_info may be called more than once for a distribution,
+ # in which case the version string already contains all tags.
+ if self.vtags and version.endswith(self.vtags):
+ return safe_version(version)
+ return safe_version(version + self.vtags)
+
+ def tags(self):
+ version = ''
+ if self.tag_build:
+ version += self.tag_build
+ if self.tag_date:
+ version += time.strftime("-%Y%m%d")
+ return version
+ vtags = property(tags)
+
+
+class egg_info(InfoCommon, Command):
description = "create a distribution's .egg-info directory"
user_options = [
@@ -133,14 +159,11 @@ class egg_info(Command):
}
def initialize_options(self):
- self.egg_name = None
- self.egg_version = None
self.egg_base = None
+ self.egg_name = None
self.egg_info = None
- self.tag_build = None
- self.tag_date = 0
+ self.egg_version = None
self.broken_egg_info = False
- self.vtags = None
####################################
# allow the 'tag_svn_revision' to be detected and
@@ -160,9 +183,7 @@ class egg_info(Command):
build tag. Install build keys in a deterministic order
to avoid arbitrary reordering on subsequent builds.
"""
- # python 2.6 compatibility
- odict = getattr(collections, 'OrderedDict', dict)
- egg_info = odict()
+ egg_info = collections.OrderedDict()
# follow the order these keys would have been added
# when PYTHONHASHSEED=0
egg_info['tag_build'] = self.tags()
@@ -170,10 +191,12 @@ class egg_info(Command):
edit_config(filename, dict(egg_info=egg_info))
def finalize_options(self):
- self.egg_name = safe_name(self.distribution.get_name())
- self.vtags = self.tags()
+ # Note: we need to capture the current value returned
+ # by `self.tagged_version()`, so we can later update
+ # `self.distribution.metadata.version` without
+ # repercussions.
+ self.egg_name = self.name
self.egg_version = self.tagged_version()
-
parsed_version = parse_version(self.egg_version)
try:
@@ -256,16 +279,9 @@ class egg_info(Command):
if not self.dry_run:
os.unlink(filename)
- def tagged_version(self):
- version = self.distribution.get_version()
- # egg_info may be called more than once for a distribution,
- # in which case the version string already contains all tags.
- if self.vtags and version.endswith(self.vtags):
- return safe_version(version)
- return safe_version(version + self.vtags)
-
def run(self):
self.mkpath(self.egg_info)
+ os.utime(self.egg_info, None)
installer = self.distribution.fetch_build_egg
for ep in iter_entry_points('egg_info.writers'):
ep.require(installer=installer)
@@ -279,14 +295,6 @@ class egg_info(Command):
self.find_sources()
- def tags(self):
- version = ''
- if self.tag_build:
- version += self.tag_build
- if self.tag_date:
- version += time.strftime("-%Y%m%d")
- return version
-
def find_sources(self):
"""Generate SOURCES.txt manifest file"""
manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
@@ -567,6 +575,12 @@ class manifest_maker(sdist):
self.filelist.extend(rcfiles)
elif os.path.exists(self.manifest):
self.read_manifest()
+
+ if os.path.exists("setup.py"):
+ # setup.py should be included by default, even if it's not
+ # the script called to create the sdist
+ self.filelist.append("setup.py")
+
ei_cmd = self.get_finalized_command('egg_info')
self.filelist.graft(ei_cmd.egg_info)
@@ -599,10 +613,7 @@ def write_pkg_info(cmd, basename, filename):
metadata = cmd.distribution.metadata
metadata.version, oldver = cmd.egg_version, metadata.version
metadata.name, oldname = cmd.egg_name, metadata.name
- metadata.long_description_content_type = getattr(
- cmd.distribution,
- 'long_description_content_type'
- )
+
try:
# write unescaped data to PKG-INFO, so older pkg_resources
# can still parse it
@@ -642,7 +653,7 @@ def write_requirements(cmd, basename, filename):
def write_setup_requirements(cmd, basename, filename):
- data = StringIO()
+ data = io.StringIO()
_write_requirements(data, cmd.distribution.setup_requires)
cmd.write_or_delete_file("setup-requirements", filename, data.getvalue())
@@ -691,7 +702,7 @@ def get_pkg_info_revision():
Get a -r### off of PKG-INFO Version in case this is an sdist of
a subversion revision.
"""
- warnings.warn("get_pkg_info_revision is deprecated.", DeprecationWarning)
+ warnings.warn("get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning)
if os.path.exists('PKG-INFO'):
with io.open('PKG-INFO') as f:
for line in f:
@@ -699,3 +710,7 @@ def get_pkg_info_revision():
if match:
return int(match.group(1))
return 0
+
+
+class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning):
+ """Class for warning about deprecations in eggInfo in setupTools. Not ignored by default, unlike DeprecationWarning."""
diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py
index edc4718b..edc4718b 100755..100644
--- a/setuptools/command/install_egg_info.py
+++ b/setuptools/command/install_egg_info.py
diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py
index 16234273..16234273 100755..100644
--- a/setuptools/command/install_scripts.py
+++ b/setuptools/command/install_scripts.py
diff --git a/setuptools/command/register.py b/setuptools/command/register.py
index 8d6336a1..98bc0156 100755..100644
--- a/setuptools/command/register.py
+++ b/setuptools/command/register.py
@@ -1,3 +1,4 @@
+from distutils import log
import distutils.command.register as orig
@@ -5,6 +6,13 @@ class register(orig.register):
__doc__ = orig.register.__doc__
def run(self):
- # Make sure that we are using valid current name/version info
- self.run_command('egg_info')
- orig.register.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
+ )
diff --git a/setuptools/command/rotate.py b/setuptools/command/rotate.py
index b89353f5..b89353f5 100755..100644
--- a/setuptools/command/rotate.py
+++ b/setuptools/command/rotate.py
diff --git a/setuptools/command/saveopts.py b/setuptools/command/saveopts.py
index 611cec55..611cec55 100755..100644
--- a/setuptools/command/saveopts.py
+++ b/setuptools/command/saveopts.py
diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
index 508148e0..bcfae4d8 100755..100644
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -51,13 +51,6 @@ class sdist(sdist_add_defaults, orig.sdist):
for cmd_name in self.get_sub_commands():
self.run_command(cmd_name)
- # Call check_metadata only if no 'check' command
- # (distutils <= 2.6)
- import distutils.command
-
- if 'check' not in distutils.command.__all__:
- self.check_metadata()
-
self.make_distribution()
dist_files = getattr(self.distribution, 'dist_files', [])
diff --git a/setuptools/command/setopt.py b/setuptools/command/setopt.py
index 7e57cc02..7e57cc02 100755..100644
--- a/setuptools/command/setopt.py
+++ b/setuptools/command/setopt.py
diff --git a/setuptools/command/test.py b/setuptools/command/test.py
index 638d0c56..dde0118c 100644
--- a/setuptools/command/test.py
+++ b/setuptools/command/test.py
@@ -3,6 +3,7 @@ import operator
import sys
import contextlib
import itertools
+import unittest
from distutils.errors import DistutilsError, DistutilsOptionError
from distutils import log
from unittest import TestLoader
@@ -14,10 +15,16 @@ 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 setuptools.py31compat import unittest_main
+
+__metaclass__ = type
class ScanningLoader(TestLoader):
+
+ def __init__(self):
+ TestLoader.__init__(self)
+ self._visited = set()
+
def loadTestsFromModule(self, module, pattern=None):
"""Return a suite of all tests cases contained in the given module
@@ -25,6 +32,10 @@ class ScanningLoader(TestLoader):
If the module has an ``additional_tests`` function, call it and add
the return value to the tests.
"""
+ if module in self._visited:
+ return None
+ self._visited.add(module)
+
tests = []
tests.append(TestLoader.loadTestsFromModule(self, module))
@@ -49,7 +60,7 @@ class ScanningLoader(TestLoader):
# adapted from jaraco.classes.properties:NonDataProperty
-class NonDataProperty(object):
+class NonDataProperty:
def __init__(self, fget):
self.fget = fget
@@ -101,6 +112,8 @@ class test(Command):
return list(self._test_args())
def _test_args(self):
+ if not self.test_suite and sys.version_info >= (2, 7):
+ yield 'discover'
if self.verbose:
yield '--verbose'
if self.test_suite:
@@ -230,12 +243,11 @@ class test(Command):
del_modules.append(name)
list(map(sys.modules.__delitem__, del_modules))
- exit_kwarg = {} if sys.version_info < (2, 7) else {"exit": False}
- test = unittest_main(
+ test = unittest.main(
None, None, self._argv,
testLoader=self._resolve_as_ep(self.test_loader),
testRunner=self._resolve_as_ep(self.test_runner),
- **exit_kwarg
+ exit=False,
)
if not test.result.wasSuccessful():
msg = 'Test failed: %s' % test.result
diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py
index a44173a9..6db8888b 100644
--- a/setuptools/command/upload.py
+++ b/setuptools/command/upload.py
@@ -1,5 +1,19 @@
+import io
+import os
+import hashlib
import getpass
+
+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.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):
@@ -7,6 +21,15 @@ class upload(orig.upload):
Override default upload behavior to obtain password
in a variety of different ways.
"""
+ 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)
@@ -22,6 +45,137 @@ class upload(orig.upload):
self._prompt_for_password()
)
+ 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.