From 5854b0eba03dd257e30efff68f1632bdec5f0416 Mon Sep 17 00:00:00 2001 From: Junhan Huang Date: Sat, 27 Oct 2018 16:26:51 -0400 Subject: Add custom deprecation warning classes `DeprecationWarning` is not visible by default in the latest versions of CPython, so this switches the deprecation warnings in setuptools and pkg_resources over to custom classes derived from `Warning` instead. Fixes issue github issue #159 Co-authored-by: Junhan Huang Co-authored-by: Marton Pono --- setuptools/command/easy_install.py | 15 +++++++++++---- setuptools/command/egg_info.py | 8 ++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'setuptools/command') diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index c670a16e..06c98271 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -40,8 +40,11 @@ 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 @@ -2077,7 +2080,7 @@ class ScriptWriter: @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) @@ -2085,7 +2088,7 @@ class ScriptWriter: @classmethod def get_script_header(cls, script_text, executable=None, wininst=False): # for backward compatibility - warnings.warn("Use get_header", DeprecationWarning, stacklevel=2) + warnings.warn("Use get_header", EasyInstallDeprecationWarning, stacklevel=2) if wininst: executable = "python.exe" return cls.get_header(script_text, executable) @@ -2120,7 +2123,7 @@ class ScriptWriter: @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 @@ -2152,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 @@ -2333,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 bd116e1f..e1022d31 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -31,7 +31,7 @@ import setuptools.unicode_utils as unicode_utils from setuptools.glob import glob from setuptools.extern import packaging - +from setuptools import SetuptoolsDeprecationWarning def translate_pattern(glob): """ @@ -696,7 +696,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: @@ -704,3 +704,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.""" -- cgit v1.2.1 From fcfe6ef3b7a49f68a9d732558ad80a7afe98aaa9 Mon Sep 17 00:00:00 2001 From: Shashank Singh Date: Sun, 28 Oct 2018 12:47:43 -0400 Subject: Add setup.py to egg-info by default Fixes GH issue #1506 --- setuptools/command/egg_info.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'setuptools/command') diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index e1022d31..d9fe3da3 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -575,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) -- cgit v1.2.1 From cbef2949856f5e0957be1cbdfdc92325f9ae9f1e Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 27 Oct 2018 17:21:11 -0400 Subject: Add upload_file to setuptools.command.upload --- setuptools/command/upload.py | 147 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 1 deletion(-) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index 72f24d8f..dae7d74d 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -1,14 +1,24 @@ +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.errors import DistutilsError + +from six.moves.urllib.request import urlopen, Request +from six.moves.urllib.error import HTTPError +from six.moves.urllib.parse import urlparse 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) @@ -33,6 +43,141 @@ 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': '1.0', + '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(), + } + comment = '' + if command == 'bdist_rpm': + dist, version, id = platform.dist() + if dist: + comment = 'built for %s %s' % (dist, version) + elif command == 'bdist_dumb': + comment = 'built for %s' % platform.platform(terse=1) + data['comment'] = 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 = self._read_pypi_response(result) + 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. -- cgit v1.2.1 From 33185837dbc1f75f7894b9cbc3e56c1c6a868c4c Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Mon, 5 Nov 2018 10:26:50 -0500 Subject: Use get_metadata_version in upload_file Previously this value was hard-coded to '1.0', which was inaccurate for many packages. Fixes #1381 --- setuptools/command/upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index dae7d74d..01fa026c 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -84,7 +84,7 @@ class upload(orig.upload): 'md5_digest': hashlib.md5(content).hexdigest(), # additional meta-data - 'metadata_version': '1.0', + 'metadata_version': str(meta.get_metadata_version()), 'summary': meta.get_description(), 'home_page': meta.get_url(), 'author': meta.get_contact(), -- cgit v1.2.1 From b5c9c5f42db36a07dc27d39c1be2a311cc567d99 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Wed, 7 Nov 2018 16:23:13 -0500 Subject: Fix gpg signature code in upload_file This fixes an issue where `distutils.spawn.spawn` was not available in the ported upload_file, which is only used when signing the data. This also adds a test that the gpg signature command is invoked and included in the uploaded data. --- setuptools/command/upload.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index 01fa026c..1851ed28 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -7,6 +7,7 @@ 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 -- cgit v1.2.1 From 727dd60f6a11f38d165250c543ba135687fa2e61 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Wed, 7 Nov 2018 16:41:19 -0500 Subject: Fix bdist_rpm and bdist_dumb in upload_file This fixes uploads when bdist_rpm or bdist_dumb are the command, both of which insert a comment about what platform they are built for. --- setuptools/command/upload.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index 1851ed28..99d86011 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -2,6 +2,7 @@ import io import os import hashlib import getpass +import platform from base64 import standard_b64encode -- cgit v1.2.1 From fe2c9e4292699635c91174bc049aefe81bf6116c Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Wed, 7 Nov 2018 17:07:58 -0500 Subject: Fix show_response behavior on Python 2 The `upload.show_response` feature was not added until Python 3. Rather than backport it, it is now enabled only if supported. This also adds a "smoke test" for the feature. --- setuptools/command/upload.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index 99d86011..f57fe796 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -172,9 +172,11 @@ class upload(orig.upload): self.announce('Server response (%s): %s' % (status, reason), log.INFO) if self.show_response: - text = self._read_pypi_response(result) - msg = '\n'.join(('-' * 75, text, '-' * 75)) - self.announce(msg, log.INFO) + 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) -- cgit v1.2.1 From 2b5b91332a01c665cab77ad7962e87525850d7f5 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Mon, 12 Nov 2018 10:08:55 -0500 Subject: Remove bdist_rpm and bdist_dumb comment This comment is not used anywhere and `platform.dist()` is deprecated. See CPython PR #10414: https://github.com/python/cpython/pull/10414 and bpo-35186: https://bugs.python.org/issue35186 --- setuptools/command/upload.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index f57fe796..3b8cab5e 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -102,14 +102,8 @@ class upload(orig.upload): 'requires': meta.get_requires(), 'obsoletes': meta.get_obsoletes(), } - comment = '' - if command == 'bdist_rpm': - dist, version, id = platform.dist() - if dist: - comment = 'built for %s %s' % (dist, version) - elif command == 'bdist_dumb': - comment = 'built for %s' % platform.platform(terse=1) - data['comment'] = comment + + data['comment'] = '' if self.sign: data['gpg_signature'] = (os.path.basename(filename) + ".asc", -- cgit v1.2.1 From ba7698287094f7274ae7cbabaf6baedc175ac213 Mon Sep 17 00:00:00 2001 From: Oleg Sharov Date: Tue, 13 Nov 2018 12:52:43 +0400 Subject: import internal version of six --- setuptools/command/upload.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index 3b8cab5e..dd17f7a9 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -12,9 +12,9 @@ from distutils.spawn import spawn from distutils.errors import DistutilsError -from six.moves.urllib.request import urlopen, Request -from six.moves.urllib.error import HTTPError -from six.moves.urllib.parse import urlparse +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): """ -- cgit v1.2.1 From 0902f02d9d68f18e906e727cbafa4a05fe5c9c91 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 24 Dec 2018 13:03:58 -0500 Subject: Access pkg_resources objects through its namespace --- setuptools/command/develop.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'setuptools/command') diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py index fdc9fc43..707494eb 100644 --- a/setuptools/command/develop.py +++ b/setuptools/command/develop.py @@ -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,13 +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( + 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): @@ -114,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) @@ -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') -- cgit v1.2.1 From b78994aa19ae0705f60e3b4b1e4087ecbe4ff0f5 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Fri, 28 Dec 2018 09:37:55 -0500 Subject: Import distribution in doctest Fixes GH issue #1612, bug introduced in commit 0902f02d9d68f18 --- setuptools/command/develop.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/command') diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py index 707494eb..009e4f93 100644 --- a/setuptools/command/develop.py +++ b/setuptools/command/develop.py @@ -202,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' -- cgit v1.2.1 From 0c9624fd5ee5abe3fb0d1e3dfa68a9cbaf261aed Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 29 Dec 2018 13:47:21 -0500 Subject: Feed the hobgoblins (delint). --- setuptools/command/upload.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/command') diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index dd17f7a9..6db8888b 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -2,7 +2,6 @@ import io import os import hashlib import getpass -import platform from base64 import standard_b64encode @@ -16,6 +15,7 @@ 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 @@ -80,7 +80,7 @@ class upload(orig.upload): 'version': meta.get_version(), # file content - 'content': (os.path.basename(filename),content), + 'content': (os.path.basename(filename), content), 'filetype': command, 'pyversion': pyversion, 'md5_digest': hashlib.md5(content).hexdigest(), -- cgit v1.2.1