Hello community, here is the log from the commit of package python3-twine for openSUSE:Factory checked in at 2016-07-15 12:51:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python3-twine (Old) and /work/SRC/openSUSE:Factory/.python3-twine.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python3-twine" Changes: -------- --- /work/SRC/openSUSE:Factory/python3-twine/python3-twine.changes 2016-06-02 09:36:09.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python3-twine.new/python3-twine.changes 2016-07-15 12:51:11.000000000 +0200 @@ -1,0 +2,48 @@ +Sat Jul 9 15:29:42 UTC 2016 - [email protected] + +- update to version 1.7.4: + * Correct a packaging error. + +------------------------------------------------------------------- +Fri Jul 8 23:37:34 UTC 2016 - [email protected] + +- update to version 1.7.3: + * :bug:`195` Fix uploads to instances of pypiserver using + "--skip-existing". We were not properly checking the return status + code on the response after attempting an upload. + * Do not generate traffic to Legacy PyPI unless we're uploading to + it or uploading to Warehouse (e.g., pypi.io). This avoids the + attempt to upload a package to the index if we can find it on + Legacy PyPI already. + +------------------------------------------------------------------- +Thu Jul 7 06:33:53 UTC 2016 - [email protected] + +- update to version 1.7.2: + * :bug:`189`, :bug:`191` Fix issue where we were checking the + existence of packages even if the user didn't specify + --skip-existing. + +------------------------------------------------------------------- +Wed Jul 6 07:22:05 UTC 2016 - [email protected] + +- update to version 1.7.1: + * Clint was not specified in the wheel metadata as a dependency. + +------------------------------------------------------------------- +Tue Jul 5 01:16:19 UTC 2016 - [email protected] + +- update to version 1.7.0: + * :feature:`142` Support --cert and --client-cert command-line flags + and config file options for feature parity with pip. This allows + users to verify connections to servers other than PyPI (e.g., + local package repositories) with different certificates. + * :feature:`152` Add progress bar to uploads. + * :feature:`162` Allow --skip-existing to work for 409 status codes. + * :feature:`167` Implement retries when the CDN in front of PyPI + gives us a 5xx error. + * :feature:`177` Switch Twine to upload to pypi.io instead of + pypi.python.org. + * :bug:`186` Allow passwords to have %s in them. + +------------------------------------------------------------------- @@ -12 +59,0 @@ - Old: ---- twine-1.6.5.tar.gz New: ---- twine-1.7.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python3-twine.spec ++++++ --- /var/tmp/diff_new_pack.75tzsH/_old 2016-07-15 12:51:12.000000000 +0200 +++ /var/tmp/diff_new_pack.75tzsH/_new 2016-07-15 12:51:12.000000000 +0200 @@ -17,7 +17,7 @@ Name: python3-twine -Version: 1.6.5 +Version: 1.7.4 Release: 0 Summary: Collection of utilities for interacting with PyPI License: Apache-2.0 ++++++ twine-1.6.5.tar.gz -> twine-1.7.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/AUTHORS new/twine-1.7.4/AUTHORS --- old/twine-1.6.5/AUTHORS 2015-09-09 03:16:47.000000000 +0200 +++ new/twine-1.7.4/AUTHORS 2016-06-15 03:16:21.000000000 +0200 @@ -14,3 +14,5 @@ Tyrel Souza <[email protected]> (https://tyrelsouza.com) Adam Talsma <[email protected]> Jens Diemer <[email protected]> (http://jensdiemer.de/) +Andrew Watts <[email protected]> +Anna Martelli Ravenscroft <[email protected]> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/PKG-INFO new/twine-1.7.4/PKG-INFO --- old/twine-1.6.5/PKG-INFO 2015-12-17 00:36:32.000000000 +0100 +++ new/twine-1.7.4/PKG-INFO 2016-07-09 13:22:23.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: twine -Version: 1.6.5 +Version: 1.7.4 Summary: Collection of utilities for interacting with PyPI Home-page: https://github.com/pypa/twine Author: Donald Stufft and individual contributors @@ -11,7 +11,7 @@ Twine is a utility for interacting `with PyPI <https://pypi.python.org/pypi/twine>`_. - Currently it only supports uploading distributions. + Currently it only supports registering projects and uploading distributions. Why Should I Use This? @@ -62,17 +62,29 @@ 1. Create some distributions in the normal way: - .. code-block:: bash + .. code-block:: bash - $ python setup.py sdist bdist_wheel + $ python setup.py sdist bdist_wheel - 2. Upload with twine: + 2. Register your project (if necessary): + + .. code-block:: bash - .. code-block:: bash + $ # One needs to be explicit here, globbing dist/* would fail. + $ twine register dist/project_name-x.y.z.tar.gz + $ twine register dist/mypkg-0.1-py2.py3-none-any.whl + + 3. Upload with twine [#]_: + + .. code-block:: bash + + $ twine upload dist/* - $ twine upload dist/* + .. [#] If you see the following error while uploading to PyPI, it probably means you need to register (see step 2):: - 3. Done! + $ HTTPError: 403 Client Error: You are not allowed to edit 'xyz' package information + + 4. Done! Options @@ -81,8 +93,10 @@ .. code-block:: bash $ twine upload -h - usage: twine upload [-h] [-r REPOSITORY] [-s] [-i IDENTITY] [-u USERNAME] - [-p PASSWORD] [-c COMMENT] + + usage: twine upload [-h] [-r REPOSITORY] [-s] [--sign-with SIGN_WITH] + [-i IDENTITY] [-u USERNAME] [-p PASSWORD] [-c COMMENT] + [--config-file CONFIG_FILE] [--skip-existing] dist [dist ...] positional arguments: @@ -93,8 +107,10 @@ optional arguments: -h, --help show this help message and exit -r REPOSITORY, --repository REPOSITORY - The repository to upload the files to + The repository to upload the files to (default: pypi) -s, --sign Sign files to upload using gpg + --sign-with SIGN_WITH + GPG program used to sign uploads (default: gpg) -i IDENTITY, --identity IDENTITY GPG identity used to sign files -u USERNAME, --username USERNAME @@ -103,8 +119,9 @@ The password to authenticate to the repository with -c COMMENT, --comment COMMENT The comment to include with the distribution file - --config-file FILE + --config-file CONFIG_FILE The .pypirc config file to use + --skip-existing Continue uploading files if one already exists Resources @@ -113,7 +130,7 @@ * `IRC <http://webchat.freenode.net?channels=%23pypa>`_ (``#pypa`` - irc.freenode.net) * `GitHub repository <https://github.com/pypa/twine>`_ - + * `Python Packaging User Guide <https://packaging.python.org/en/latest/distributing/>`_ Contributing ------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/README.rst new/twine-1.7.4/README.rst --- old/twine-1.6.5/README.rst 2015-09-13 22:06:52.000000000 +0200 +++ new/twine-1.7.4/README.rst 2016-06-15 03:16:21.000000000 +0200 @@ -3,7 +3,7 @@ Twine is a utility for interacting `with PyPI <https://pypi.python.org/pypi/twine>`_. -Currently it only supports uploading distributions. +Currently it only supports registering projects and uploading distributions. Why Should I Use This? @@ -54,17 +54,29 @@ 1. Create some distributions in the normal way: -.. code-block:: bash + .. code-block:: bash - $ python setup.py sdist bdist_wheel + $ python setup.py sdist bdist_wheel -2. Upload with twine: +2. Register your project (if necessary): + + .. code-block:: bash -.. code-block:: bash + $ # One needs to be explicit here, globbing dist/* would fail. + $ twine register dist/project_name-x.y.z.tar.gz + $ twine register dist/mypkg-0.1-py2.py3-none-any.whl + +3. Upload with twine [#]_: + + .. code-block:: bash + + $ twine upload dist/* - $ twine upload dist/* + .. [#] If you see the following error while uploading to PyPI, it probably means you need to register (see step 2):: -3. Done! + $ HTTPError: 403 Client Error: You are not allowed to edit 'xyz' package information + +4. Done! Options @@ -73,8 +85,10 @@ .. code-block:: bash $ twine upload -h - usage: twine upload [-h] [-r REPOSITORY] [-s] [-i IDENTITY] [-u USERNAME] - [-p PASSWORD] [-c COMMENT] + + usage: twine upload [-h] [-r REPOSITORY] [-s] [--sign-with SIGN_WITH] + [-i IDENTITY] [-u USERNAME] [-p PASSWORD] [-c COMMENT] + [--config-file CONFIG_FILE] [--skip-existing] dist [dist ...] positional arguments: @@ -85,8 +99,10 @@ optional arguments: -h, --help show this help message and exit -r REPOSITORY, --repository REPOSITORY - The repository to upload the files to + The repository to upload the files to (default: pypi) -s, --sign Sign files to upload using gpg + --sign-with SIGN_WITH + GPG program used to sign uploads (default: gpg) -i IDENTITY, --identity IDENTITY GPG identity used to sign files -u USERNAME, --username USERNAME @@ -95,8 +111,9 @@ The password to authenticate to the repository with -c COMMENT, --comment COMMENT The comment to include with the distribution file - --config-file FILE + --config-file CONFIG_FILE The .pypirc config file to use + --skip-existing Continue uploading files if one already exists Resources @@ -105,7 +122,7 @@ * `IRC <http://webchat.freenode.net?channels=%23pypa>`_ (``#pypa`` - irc.freenode.net) * `GitHub repository <https://github.com/pypa/twine>`_ - +* `Python Packaging User Guide <https://packaging.python.org/en/latest/distributing/>`_ Contributing ------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/docs/changelog.rst new/twine-1.7.4/docs/changelog.rst --- old/twine-1.6.5/docs/changelog.rst 2015-12-17 00:34:22.000000000 +0100 +++ new/twine-1.7.4/docs/changelog.rst 2016-07-09 13:21:25.000000000 +0200 @@ -4,6 +4,48 @@ Changelog ========= +* :release:`1.7.4 <2016-07-09>` + + * Correct a packaging error. + +* :release:`1.7.3 <2016-07-08>` + + * :bug:`195` Fix uploads to instances of pypiserver using + ``--skip-existing``. We were not properly checking the return status code + on the response after attempting an upload. + + * Do not generate traffic to Legacy PyPI unless we're uploading to it or + uploading to Warehouse (e.g., pypi.io). This avoids the attempt to upload + a package to the index if we can find it on Legacy PyPI already. + +* :release:`1.7.2 <2016-07-05>` + + * :bug:`189`, :bug:`191` Fix issue where we were checking the existence of + packages even if the user didn't specify ``--skip-existing``. + +* :release:`1.7.1 <2016-07-05>` + + * :bug:`187` Clint was not specified in the wheel metadata as a dependency. + +* :release:`1.7.0 <2016-07-04>` + + * :feature:`142` Support ``--cert`` and ``--client-cert`` command-line flags + and config file options for feature parity with pip. This allows users to + verify connections to servers other than PyPI (e.g., local package + repositories) with different certificates. + + * :feature:`152` Add progress bar to uploads. + + * :feature:`162` Allow ``--skip-existing`` to work for 409 status codes. + + * :feature:`167` Implement retries when the CDN in front of PyPI gives us a + 5xx error. + + * :feature:`177` Switch Twine to upload to pypi.io instead of + pypi.python.org. + + * :bug:`186` Allow passwords to have ``%``\ s in them. + * :release:`1.6.5 <2015-12-16>` * :bug:`155` Bump requests-toolbelt version to ensure we avoid diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/docs/conf.py new/twine-1.7.4/docs/conf.py --- old/twine-1.6.5/docs/conf.py 2015-04-16 06:50:41.000000000 +0200 +++ new/twine-1.7.4/docs/conf.py 2016-06-15 03:16:21.000000000 +0200 @@ -12,14 +12,14 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys -import os +# import sys +# import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) -sys.path.insert(0, os.path.abspath(os.pardir)) +# sys.path.insert(0, os.path.abspath(os.pardir)) import twine diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/setup.cfg new/twine-1.7.4/setup.cfg --- old/twine-1.6.5/setup.cfg 2015-12-17 00:36:32.000000000 +0100 +++ new/twine-1.7.4/setup.cfg 2016-07-09 13:22:23.000000000 +0200 @@ -8,8 +8,9 @@ [metadata] requires-dist = - requests >= 2.3.0 - requests-toolbelt >= 0.4.0 + clint + requests >= 2.5.0 + requests-toolbelt >= 0.5.1 pkginfo >= 1.0 setuptools >= 0.7.0 argparse; python_version == '2.6' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/setup.py new/twine-1.7.4/setup.py --- old/twine-1.6.5/setup.py 2015-12-17 00:32:09.000000000 +0100 +++ new/twine-1.7.4/setup.py 2016-06-15 03:16:21.000000000 +0200 @@ -19,8 +19,9 @@ install_requires = [ + "clint", "pkginfo >= 1.0", - "requests >= 2.3.0", + "requests >= 2.5.0", "requests-toolbelt >= 0.5.1", "setuptools >= 0.7.0", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/tests/test_repository.py new/twine-1.7.4/tests/test_repository.py --- old/twine-1.6.5/tests/test_repository.py 2015-12-17 00:32:47.000000000 +0100 +++ new/twine-1.7.4/tests/test_repository.py 2016-07-04 21:45:58.000000000 +0200 @@ -47,3 +47,46 @@ tuples = repository.Repository._convert_data_to_list_of_tuples(data) assert tuples == [('platform', 'UNKNOWN'), ('platform', 'ANOTHERPLATFORM')] + + +def test_set_client_certificate(): + repo = repository.Repository( + repository_url='https://pypi.python.org/pypi', + username='username', + password='password', + ) + + assert repo.session.cert is None + + repo.set_client_certificate(('/path/to/cert', '/path/to/key')) + assert repo.session.cert == ('/path/to/cert', '/path/to/key') + + +def test_set_certificate_authority(): + repo = repository.Repository( + repository_url='https://pypi.python.org/pypi', + username='username', + password='password', + ) + + assert repo.session.verify is True + + repo.set_certificate_authority('/path/to/cert') + assert repo.session.verify == '/path/to/cert' + + +def test_make_user_agent_string(): + repo = repository.Repository( + repository_url='https://pypi.python.org/pypi', + username='username', + password='password', + ) + + assert 'User-Agent' in repo.session.headers + + user_agent = repo.session.headers['User-Agent'] + assert 'twine/' in user_agent + assert 'requests/' in user_agent + assert 'requests-toolbelt/' in user_agent + assert 'pkginfo/' in user_agent + assert 'setuptools/' in user_agent diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/tests/test_upload.py new/twine-1.7.4/tests/test_upload.py --- old/twine-1.6.5/tests/test_upload.py 2015-12-17 00:32:47.000000000 +0100 +++ new/twine-1.7.4/tests/test_upload.py 2016-06-15 03:16:21.000000000 +0200 @@ -78,6 +78,7 @@ try: upload.upload(dists=dists, repository="pypi", sign=None, identity=None, username=None, password=None, comment=None, + cert=None, client_cert=None, sign_with=None, config_file=pypirc, skip_existing=False) except KeyError as err: assert err.args[0] == ( @@ -94,6 +95,19 @@ reason='A file named "twine-1.5.0-py2.py3-none-any.whl" already ' 'exists for twine-1.5.0.') + pkg = package.PackageFile.from_filename(WHEEL_FIXTURE, None) + assert upload.skip_upload(response=response, + skip_existing=True, + package=pkg) is True + + +def test_skip_existing_skips_files_already_on_pypiserver(monkeypatch): + # pypiserver (https://pypi.python.org/pypi/pypiserver) responds with 409 + response = pretend.stub( + status_code=409, + reason='A file named "twine-1.5.0-py2.py3-none-any.whl" already ' + 'exists for twine-1.5.0.') + pkg = package.PackageFile.from_filename(WHEEL_FIXTURE, None) assert upload.skip_upload(response=response, skip_existing=True, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine/__init__.py new/twine-1.7.4/twine/__init__.py --- old/twine-1.6.5/twine/__init__.py 2015-12-17 00:34:33.000000000 +0100 +++ new/twine-1.7.4/twine/__init__.py 2016-07-09 13:21:34.000000000 +0200 @@ -23,7 +23,7 @@ __summary__ = "Collection of utilities for interacting with PyPI" __uri__ = "https://github.com/pypa/twine" -__version__ = "1.6.5" +__version__ = "1.7.4" __author__ = "Donald Stufft and individual contributors" __email__ = "[email protected]" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine/cli.py new/twine-1.7.4/twine/cli.py --- old/twine-1.6.5/twine/cli.py 2015-09-14 15:56:03.000000000 +0200 +++ new/twine-1.7.4/twine/cli.py 2016-07-04 21:45:58.000000000 +0200 @@ -18,7 +18,9 @@ import pkg_resources import setuptools +import clint import requests +import requests_toolbelt import pkginfo import twine @@ -30,13 +32,20 @@ return dict((c.name, c) for c in registered_commands) +def list_dependencies_and_versions(): + return [ + ('pkginfo', Installed(pkginfo).version), + ('requests', requests.__version__), + ('setuptools', setuptools.__version__), + ('requests-toolbelt', requests_toolbelt.__version__), + ('clint', clint.__version__), + ] + + def dep_versions(): - return 'pkginfo: {0}, requests: {1}, setuptools: {2}'.format( - Installed(pkginfo).version, - # __version__ is always defined but requests does not always have - # PKG-INFO to read from - requests.__version__, - setuptools.__version__, + return ', '.join( + '{0}: {1}'.format(*dependency) + for dependency in list_dependencies_and_versions() ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine/commands/register.py new/twine-1.7.4/twine/commands/register.py --- old/twine-1.6.5/twine/commands/register.py 2015-12-17 00:32:47.000000000 +0100 +++ new/twine-1.7.4/twine/commands/register.py 2015-12-17 00:37:02.000000000 +0100 @@ -23,7 +23,8 @@ from twine import utils -def register(package, repository, username, password, comment, config_file): +def register(package, repository, username, password, comment, config_file, + cert, client_cert): config = utils.get_repository_from_config(config_file, repository) config["repository"] = utils.normalize_repository_url( config["repository"] @@ -33,8 +34,12 @@ username = utils.get_username(username, config) password = utils.get_password(password, config) + ca_cert = utils.get_cacert(cert, config) + client_cert = utils.get_clientcert(client_cert, config) repository = Repository(config["repository"], username, password) + repository.set_certificate_authority(ca_cert) + repository.set_client_certificate(client_cert) if not os.path.exists(package): raise exc.PackageNotFound( @@ -79,6 +84,17 @@ help="The .pypirc config file to use", ) parser.add_argument( + "--cert", + metavar="path", + help="Path to alternate CA bundle", + ) + parser.add_argument( + "--client-cert", + metavar="path", + help="Path to SSL client certificate, a single file containing the " + "private key and the certificate in PEM forma", + ) + parser.add_argument( "package", metavar="package", help="File from which we read the package metadata", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine/commands/upload.py new/twine-1.7.4/twine/commands/upload.py --- old/twine-1.6.5/twine/commands/upload.py 2015-12-17 00:32:47.000000000 +0100 +++ new/twine-1.7.4/twine/commands/upload.py 2016-07-09 13:20:09.000000000 +0200 @@ -55,14 +55,24 @@ def skip_upload(response, skip_existing, package): filename = package.basefilename - msg = 'A file named "{0}" already exists for'.format(filename) - return (response.status_code == 400 and - response.reason.startswith(msg) and - skip_existing) + # NOTE(sigmavirus24): Old PyPI returns the first message while Warehouse + # returns the latter. This papers over the differences. + msg = ('A file named "{0}" already exists for'.format(filename), + 'File already exists') + # NOTE(sigmavirus24): PyPI presently returns a 400 status code with the + # error message in the reason attribute. Other implementations return a + # 409 status code. We only want to skip an upload if: + # 1. The user has told us to skip existing packages (skip_existing is + # True) AND + # 2. a) The response status code is 409 OR + # 2. b) The response status code is 400 AND it has a reason that matches + # what we expect PyPI to return to us. + return (skip_existing and (response.status_code == 409 or + (response.status_code == 400 and response.reason.startswith(msg)))) def upload(dists, repository, sign, identity, username, password, comment, - sign_with, config_file, skip_existing): + sign_with, config_file, skip_existing, cert, client_cert): # Check that a nonsensical option wasn't given if not sign and identity: raise ValueError("sign must be given along with identity") @@ -85,11 +95,26 @@ username = utils.get_username(username, config) password = utils.get_password(password, config) + ca_cert = utils.get_cacert(cert, config) + client_cert = utils.get_clientcert(client_cert, config) repository = Repository(config["repository"], username, password) + repository.set_certificate_authority(ca_cert) + repository.set_client_certificate(client_cert) for filename in uploads: package = PackageFile.from_filename(filename, comment) + skip_message = ( + " Skipping {0} because it appears to already exist".format( + package.basefilename) + ) + + # Note: The skip_existing check *needs* to be first, because otherwise + # we're going to generate extra HTTP requests against a hardcoded + # URL for no reason. + if skip_existing and repository.package_is_uploaded(package): + print(skip_message) + continue signed_name = package.signed_basefilename if signed_name in signatures: @@ -109,10 +134,8 @@ ' Aborting...').format(config["repository"], resp.headers["location"])) - # Otherwise, raise an HTTPError based on the status code. if skip_upload(resp, skip_existing, package): - print(" Skipping {0} because it appears to already exist".format( - package.basefilename)) + print(skip_message) continue resp.raise_for_status() @@ -165,7 +188,20 @@ "--skip-existing", default=False, action="store_true", - help="Continue uploading files if one already exists", + help="Continue uploading files if one already exists. (Only valid " + "when uploading to PyPI. Other implementations may not support " + "this.)", + ) + parser.add_argument( + "--cert", + metavar="path", + help="Path to alternate CA bundle", + ) + parser.add_argument( + "--client-cert", + metavar="path", + help="Path to SSL client certificate, a single file containing the " + "private key and the certificate in PEM forma", ) parser.add_argument( "dists", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine/repository.py new/twine-1.7.4/twine/repository.py --- old/twine-1.6.5/twine/repository.py 2015-12-17 00:32:47.000000000 +0100 +++ new/twine-1.7.4/twine/repository.py 2016-07-09 13:20:09.000000000 +0200 @@ -13,18 +13,50 @@ # limitations under the License. from __future__ import absolute_import, unicode_literals, print_function +from clint.textui.progress import Bar as ProgressBar + import requests -from requests_toolbelt.multipart import MultipartEncoder +from requests import adapters +from requests import codes +from requests.packages.urllib3 import util +from requests_toolbelt.multipart import ( + MultipartEncoder, MultipartEncoderMonitor +) +from requests_toolbelt.utils.user_agent import user_agent +import twine KEYWORDS_TO_NOT_FLATTEN = set(["gpg_signature", "content"]) +LEGACY_PYPI = 'https://pypi.python.org/' +WAREHOUSE = 'https://upload.pypi.io/' + class Repository(object): def __init__(self, repository_url, username, password): self.url = repository_url self.session = requests.session() self.session.auth = (username, password) + self.session.headers['User-Agent'] = self._make_user_agent_string() + for scheme in ('http://', 'https://'): + self.session.mount(scheme, self._make_adapter_with_retries()) + self._releases_json_data = {} + + @staticmethod + def _make_adapter_with_retries(): + retry = util.Retry( + connect=5, + total=10, + method_whitelist=['GET'], + status_forcelist=[500, 501, 502, 503], + ) + return adapters.HTTPAdapter(max_retries=retry) + + @staticmethod + def _make_user_agent_string(): + from twine import cli + dependencies = cli.list_dependencies_and_versions() + return user_agent('twine', twine.__version__, extras=dependencies) def close(self): self.session.close() @@ -41,6 +73,14 @@ data_to_send.append((key, item)) return data_to_send + def set_certificate_authority(self, cacert): + if cacert: + self.session.verify = cacert + + def set_client_certificate(self, clientcert): + if clientcert: + self.session.cert = clientcert + def register(self, package): data = package.metadata_dictionary() data.update({ @@ -62,7 +102,7 @@ resp.close() return resp - def upload(self, package): + def _upload(self, package): data = package.metadata_dictionary() data.update({ # action @@ -80,12 +120,70 @@ (package.basefilename, fp, "application/octet-stream"), )) encoder = MultipartEncoder(data_to_send) + bar = ProgressBar(expected_size=encoder.len, filled_char='=') + monitor = MultipartEncoderMonitor( + encoder, lambda monitor: bar.show(monitor.bytes_read) + ) resp = self.session.post( self.url, - data=encoder, + data=monitor, allow_redirects=False, - headers={'Content-Type': encoder.content_type}, + headers={'Content-Type': monitor.content_type}, ) + bar.done() return resp + + def upload(self, package, max_redirects=5): + number_of_redirects = 0 + while number_of_redirects < max_redirects: + resp = self._upload(package) + + if resp.status_code == codes.OK: + return resp + if 500 <= resp.status_code < 600: + number_of_redirects += 1 + print('Received "{status_code}: {reason}" Package upload ' + 'appears to have failed. Retry {retry} of 5'.format( + status_code=resp.status_code, + reason=resp.reason, + retry=number_of_redirects, + )) + else: + return resp + + return resp + + def package_is_uploaded(self, package, bypass_cache=False): + # NOTE(sigmavirus24): Not all indices are PyPI and pypi.io doesn't + # have a similar interface for finding the package versions. + if not self.url.startswith((LEGACY_PYPI, WAREHOUSE)): + return False + + safe_name = package.safe_name + releases = None + + if not bypass_cache: + releases = self._releases_json_data.get(safe_name) + + if releases is None: + url = '{url}pypi/{package}/json'.format(package=safe_name, + url=LEGACY_PYPI) + headers = {'Accept': 'application/json'} + response = self.session.get(url, headers=headers) + releases = response.json()['releases'] + self._releases_json_data[safe_name] = releases + + packages = releases.get(package.metadata.version, []) + + for uploaded_package in packages: + if uploaded_package['filename'] == package.basefilename: + return True + + return False + + def verify_package_integrity(self, package): + # TODO(sigmavirus24): Add a way for users to download the package and + # check it's hash against what it has locally. + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine/utils.py new/twine-1.7.4/twine/utils.py --- old/twine-1.6.5/twine/utils.py 2015-12-17 00:32:47.000000000 +0100 +++ new/twine-1.7.4/twine/utils.py 2016-07-04 21:45:58.000000000 +0200 @@ -37,7 +37,7 @@ input_func = raw_input -DEFAULT_REPOSITORY = "https://pypi.python.org/pypi" +DEFAULT_REPOSITORY = "https://upload.pypi.io/legacy/" def get_config(path="~/.pypirc"): @@ -52,12 +52,12 @@ } # Parse the rc file - parser = configparser.ConfigParser() + parser = configparser.RawConfigParser() parser.read(path) # Get a list of repositories from the config file - if (parser.has_section("distutils") - and parser.has_option("distutils", "index-servers")): + if (parser.has_section("distutils") and + parser.has_option("distutils", "index-servers")): repositories = parser.get("distutils", "index-servers").split() else: repositories = ["pypi"] @@ -116,14 +116,15 @@ return urlunparse(parsed) -def get_userpass_value(cli_value, config, key, prompt_strategy): +def get_userpass_value(cli_value, config, key, prompt_strategy=None): """Gets the username / password from config. Uses the following rules: 1. If it is specified on the cli (`cli_value`), use that. 2. If `config[key]` is specified, use that. - 3. Otherwise prompt using `prompt_strategy`. + 3. If `prompt_strategy`, prompt using `prompt_strategy`. + 4. Otherwise return None :param cli_value: The value supplied from the command line or `None`. :type cli_value: unicode or `None` @@ -140,8 +141,10 @@ return cli_value elif config.get(key): return config[key] - else: + elif prompt_strategy: return prompt_strategy() + else: + return None def password_prompt(prompt_text): # Always expects unicode for our own sanity @@ -161,3 +164,11 @@ key='password', prompt_strategy=password_prompt('Enter your password: '), ) +get_cacert = functools.partial( + get_userpass_value, + key='ca_cert', +) +get_clientcert = functools.partial( + get_userpass_value, + key='client_cert', +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine.egg-info/PKG-INFO new/twine-1.7.4/twine.egg-info/PKG-INFO --- old/twine-1.6.5/twine.egg-info/PKG-INFO 2015-12-17 00:36:32.000000000 +0100 +++ new/twine-1.7.4/twine.egg-info/PKG-INFO 2016-07-09 13:22:22.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: twine -Version: 1.6.5 +Version: 1.7.4 Summary: Collection of utilities for interacting with PyPI Home-page: https://github.com/pypa/twine Author: Donald Stufft and individual contributors @@ -11,7 +11,7 @@ Twine is a utility for interacting `with PyPI <https://pypi.python.org/pypi/twine>`_. - Currently it only supports uploading distributions. + Currently it only supports registering projects and uploading distributions. Why Should I Use This? @@ -62,17 +62,29 @@ 1. Create some distributions in the normal way: - .. code-block:: bash + .. code-block:: bash - $ python setup.py sdist bdist_wheel + $ python setup.py sdist bdist_wheel - 2. Upload with twine: + 2. Register your project (if necessary): + + .. code-block:: bash - .. code-block:: bash + $ # One needs to be explicit here, globbing dist/* would fail. + $ twine register dist/project_name-x.y.z.tar.gz + $ twine register dist/mypkg-0.1-py2.py3-none-any.whl + + 3. Upload with twine [#]_: + + .. code-block:: bash + + $ twine upload dist/* - $ twine upload dist/* + .. [#] If you see the following error while uploading to PyPI, it probably means you need to register (see step 2):: - 3. Done! + $ HTTPError: 403 Client Error: You are not allowed to edit 'xyz' package information + + 4. Done! Options @@ -81,8 +93,10 @@ .. code-block:: bash $ twine upload -h - usage: twine upload [-h] [-r REPOSITORY] [-s] [-i IDENTITY] [-u USERNAME] - [-p PASSWORD] [-c COMMENT] + + usage: twine upload [-h] [-r REPOSITORY] [-s] [--sign-with SIGN_WITH] + [-i IDENTITY] [-u USERNAME] [-p PASSWORD] [-c COMMENT] + [--config-file CONFIG_FILE] [--skip-existing] dist [dist ...] positional arguments: @@ -93,8 +107,10 @@ optional arguments: -h, --help show this help message and exit -r REPOSITORY, --repository REPOSITORY - The repository to upload the files to + The repository to upload the files to (default: pypi) -s, --sign Sign files to upload using gpg + --sign-with SIGN_WITH + GPG program used to sign uploads (default: gpg) -i IDENTITY, --identity IDENTITY GPG identity used to sign files -u USERNAME, --username USERNAME @@ -103,8 +119,9 @@ The password to authenticate to the repository with -c COMMENT, --comment COMMENT The comment to include with the distribution file - --config-file FILE + --config-file CONFIG_FILE The .pypirc config file to use + --skip-existing Continue uploading files if one already exists Resources @@ -113,7 +130,7 @@ * `IRC <http://webchat.freenode.net?channels=%23pypa>`_ (``#pypa`` - irc.freenode.net) * `GitHub repository <https://github.com/pypa/twine>`_ - + * `Python Packaging User Guide <https://packaging.python.org/en/latest/distributing/>`_ Contributing ------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.6.5/twine.egg-info/requires.txt new/twine-1.7.4/twine.egg-info/requires.txt --- old/twine-1.6.5/twine.egg-info/requires.txt 2015-12-17 00:36:32.000000000 +0100 +++ new/twine-1.7.4/twine.egg-info/requires.txt 2016-07-09 13:22:22.000000000 +0200 @@ -1,4 +1,5 @@ +clint pkginfo >= 1.0 -requests >= 2.3.0 +requests >= 2.5.0 requests-toolbelt >= 0.5.1 setuptools >= 0.7.0
