Hello community, here is the log from the commit of package python-twine for openSUSE:Factory checked in at 2019-03-18 10:37:34 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-twine (Old) and /work/SRC/openSUSE:Factory/.python-twine.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-twine" Mon Mar 18 10:37:34 2019 rev:6 rq:680764 version:1.13.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-twine/python-twine.changes 2019-02-13 10:00:16.965637102 +0100 +++ /work/SRC/openSUSE:Factory/.python-twine.new.28833/python-twine.changes 2019-03-18 10:37:45.383499576 +0100 @@ -1,0 +2,29 @@ +Sat Mar 2 04:53:11 UTC 2019 - Arun Persaud <[email protected]> + +- specfile: + * be more specific in %files section + * remove patch fix-keyring-support.patch, included upstream + +- update to version 1.13.0: + * bug`452` Restore prompts while retaining support for suppressing + prompts. + * bug`447` Avoid requests-toolbelt to 0.9.0 to prevent attempting to + use openssl when it isn't available. + * :feature:`427` Add disable_progress_bar option to disable tqdm. + * :feature:`426` Allow defining an empty username and password in + .pypirc. + * bug`441` Only install pyblake2 if needed. + * bug`444` Use io.StringIO instead of StringIO. + * bug`436` Use modern Python language features. + * :support:`439` Refactor tox env and travis config. + * bug`435` Specify python_requires in setup.py + * bug`432` Use https URLs everywhere. + * bug`428` Fix --skip-existing for Nexus Repos. + * :feature:`419` Support keyring.get_credential. + * :feature:`418` Support keyring.get_username_and_password. + * bug`421` Remove unnecessary usage of readme_render.markdown. + * :feature:" Add Python 3.7 to classifiers. + * bug`412` Don't crash if there's no package description. + * bug`408` Fix keyring support. + +------------------------------------------------------------------- Old: ---- fix-keyring-support.patch twine-1.12.1.tar.gz New: ---- twine-1.13.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-twine.spec ++++++ --- /var/tmp/diff_new_pack.PJt0q6/_old 2019-03-18 10:37:51.455498259 +0100 +++ /var/tmp/diff_new_pack.PJt0q6/_new 2019-03-18 10:37:51.459498258 +0100 @@ -18,15 +18,13 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-twine -Version: 1.12.1 +Version: 1.13.0 Release: 0 Summary: Collection of utilities for interacting with PyPI License: Apache-2.0 Group: Development/Languages/Python URL: https://github.com/pypa/twine Source: https://files.pythonhosted.org/packages/source/t/twine/twine-%{version}.tar.gz -# gh#pypa/twine#408 -Patch0: fix-keyring-support.patch BuildRequires: %{python_module pkginfo >= 1.4.2} BuildRequires: %{python_module pretend} BuildRequires: %{python_module pytest} @@ -61,7 +59,6 @@ %prep %setup -q -n twine-%{version} -%autopatch -p1 sed -i '1s/^#!.*//' twine/__main__.py @@ -85,7 +82,10 @@ %files %{python_files} %doc AUTHORS README.rst %license LICENSE -%{python_sitelib}/* +%dir %{python_sitelib}/twine +%dir %{python_sitelib}/twine-%{version}-py*.egg-info +%{python_sitelib}/twine/* +%{python_sitelib}/twine-%{version}-py*.egg-info/* %python_alternative %{_bindir}/twine %changelog ++++++ twine-1.12.1.tar.gz -> twine-1.13.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/AUTHORS new/twine-1.13.0/AUTHORS --- old/twine-1.12.1/AUTHORS 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/AUTHORS 2019-02-13 21:35:39.000000000 +0100 @@ -18,8 +18,9 @@ Anna Martelli Ravenscroft <[email protected]> Sumana Harihareswara <[email protected]> Dustin Ingram <[email protected]> (https://di.codes) -Jesse Jarzynka <[email protected]> (http://jessejoe.com) +Jesse Jarzynka <[email protected]> (https://www.jessejoe.com/) László Kiss Kollár <[email protected]> Frances Hocutt <[email protected]> Tathagata Dasgupta <[email protected]> -Wasim Thabraze <[email protected]> \ No newline at end of file +Wasim Thabraze <[email protected]> +Varun Kamath <[email protected]> \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/LICENSE new/twine-1.13.0/LICENSE --- old/twine-1.12.1/LICENSE 2017-01-19 15:23:11.000000000 +0100 +++ new/twine-1.13.0/LICENSE 2019-02-13 21:35:39.000000000 +0100 @@ -1,6 +1,6 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/PKG-INFO new/twine-1.13.0/PKG-INFO --- old/twine-1.12.1/PKG-INFO 2018-09-24 20:41:42.000000000 +0200 +++ new/twine-1.13.0/PKG-INFO 2019-02-13 22:38:54.000000000 +0100 @@ -1,15 +1,19 @@ Metadata-Version: 2.1 Name: twine -Version: 1.12.1 +Version: 1.13.0 Summary: Collection of utilities for publishing packages on PyPI Home-page: https://twine.readthedocs.io/ Author: Donald Stufft and individual contributors Author-email: [email protected] License: Apache License, Version 2.0 -Project-URL: Twine source, https://github.com/pypa/twine/ Project-URL: Packaging tutorial, https://packaging.python.org/tutorials/distributing-packages/ +Project-URL: Travis CI, https://travis-ci.org/pypa/twine Project-URL: Twine documentation, https://twine.readthedocs.io/en/latest/ -Description: twine +Project-URL: Twine source, https://github.com/pypa/twine/ +Description: .. image:: https://img.shields.io/travis/pypa/twine/master.svg?label=travis-ci + :target: https://travis-ci.org/pypa/twine + + twine ===== .. rtd-inclusion-marker-do-not-remove @@ -148,7 +152,7 @@ Disabling Keyring ^^^^^^^^^^^^^^^^^ - In some cases, the presence of keyring may be problemmatic. To disable + In some cases, the presence of keyring may be problematic. To disable keyring and defer to a prompt for passwords, uninstall ``keyring`` or if that's not an option, you can also configure keyring to be disabled. @@ -171,6 +175,7 @@ [-s] [--sign-with SIGN_WITH] [-i IDENTITY] [-u USERNAME] [-p PASSWORD] [-c COMMENT] [--config-file CONFIG_FILE] [--skip-existing] [--cert path] [--client-cert path] + [--verbose] [--disable-progress-bar] dist [dist ...] positional arguments: @@ -215,6 +220,9 @@ --client-cert path Path to SSL client certificate, a single file containing the private key and the certificate in PEM format. + --verbose Show verbose output. + --disable-progress-bar + Disable the progress bar. ``twine check`` ^^^^^^^^^^^^^^^ @@ -357,7 +365,9 @@ Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy -Provides-Extra: keyring +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* Provides-Extra: with-blake2 +Provides-Extra: keyring diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/README.rst new/twine-1.13.0/README.rst --- old/twine-1.12.1/README.rst 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/README.rst 2019-02-13 21:35:39.000000000 +0100 @@ -1,3 +1,6 @@ +.. image:: https://img.shields.io/travis/pypa/twine/master.svg?label=travis-ci + :target: https://travis-ci.org/pypa/twine + twine ===== @@ -137,7 +140,7 @@ Disabling Keyring ^^^^^^^^^^^^^^^^^ -In some cases, the presence of keyring may be problemmatic. To disable +In some cases, the presence of keyring may be problematic. To disable keyring and defer to a prompt for passwords, uninstall ``keyring`` or if that's not an option, you can also configure keyring to be disabled. @@ -160,6 +163,7 @@ [-s] [--sign-with SIGN_WITH] [-i IDENTITY] [-u USERNAME] [-p PASSWORD] [-c COMMENT] [--config-file CONFIG_FILE] [--skip-existing] [--cert path] [--client-cert path] + [--verbose] [--disable-progress-bar] dist [dist ...] positional arguments: @@ -204,6 +208,9 @@ --client-cert path Path to SSL client certificate, a single file containing the private key and the certificate in PEM format. + --verbose Show verbose output. + --disable-progress-bar + Disable the progress bar. ``twine check`` ^^^^^^^^^^^^^^^ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/docs/changelog.rst new/twine-1.13.0/docs/changelog.rst --- old/twine-1.12.1/docs/changelog.rst 2018-09-24 20:40:31.000000000 +0200 +++ new/twine-1.13.0/docs/changelog.rst 2019-02-13 22:37:01.000000000 +0100 @@ -3,7 +3,25 @@ ========= Changelog ========= - +* :release:`1.13.0 <2019-02-13>` +* :bug:`452` Restore prompts while retaining support for suppressing prompts. +* :bug:`447` Avoid requests-toolbelt to 0.9.0 to prevent attempting to use + openssl when it isn't available. +* :feature:`427` Add disable_progress_bar option to disable tqdm. +* :feature:`426` Allow defining an empty username and password in .pypirc. +* :bug:`441` Only install pyblake2 if needed. +* :bug:`444` Use io.StringIO instead of StringIO. +* :bug:`436` Use modern Python language features. +* :support:`439` Refactor tox env and travis config. +* :bug:`435` Specify python_requires in setup.py +* :bug:`432` Use https URLs everywhere. +* :bug:`428` Fix --skip-existing for Nexus Repos. +* :feature:`419` Support keyring.get_credential. +* :feature:`418` Support keyring.get_username_and_password. +* :bug:`421` Remove unnecessary usage of readme_render.markdown. +* :feature:`` Add Python 3.7 to classifiers. +* :bug:`412` Don't crash if there's no package description. +* :bug:`408` Fix keyring support. * :release:`1.12.1 <2018-09-24>` * :bug:`404` Fix regression with upload exit code * :release:`1.12.0 <2018-09-24>` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/setup.cfg new/twine-1.13.0/setup.cfg --- old/twine-1.12.1/setup.cfg 2018-09-24 20:41:42.000000000 +0200 +++ new/twine-1.13.0/setup.cfg 2019-02-13 22:38:54.000000000 +0100 @@ -10,14 +10,6 @@ [metadata] license_file = LICENSE -requires-dist = - tqdm >= 4.14 - requests >= 2.5.0, != 2.15, != 2.16 - requests-toolbelt >= 0.8.0 - pkginfo >= 1.4.2 - setuptools >= 0.7.0 - pyblake2; extra == 'with-blake2' and python_version < '3.6' - keyring; extra == 'keyring' [egg_info] tag_build = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/setup.py new/twine-1.13.0/setup.py --- old/twine-1.12.1/setup.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/setup.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,19 +13,9 @@ # limitations under the License. from setuptools import setup -import sys - import twine -blake2_requires = [] - -if sys.version_info[:2] < (3, 6): - blake2_requires += [ - "pyblake2", - ] - - setup( name=twine.__title__, version=twine.__version__, @@ -36,6 +26,7 @@ url=twine.__uri__, project_urls={ 'Packaging tutorial': 'https://packaging.python.org/tutorials/distributing-packages/', + 'Travis CI': 'https://travis-ci.org/pypa/twine', 'Twine documentation': 'https://twine.readthedocs.io/en/latest/', 'Twine source': 'https://github.com/pypa/twine/', }, @@ -59,6 +50,7 @@ "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ], @@ -76,16 +68,19 @@ ], }, + python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", install_requires=[ "pkginfo >= 1.4.2", "readme_renderer >= 21.0", "requests >= 2.5.0, != 2.15, != 2.16", - "requests-toolbelt >= 0.8.0", + "requests-toolbelt >= 0.8.0, != 0.9.0", "setuptools >= 0.7.0", "tqdm >= 4.14", ], extras_require={ - 'with-blake2': blake2_requires, + 'with-blake2': [ + 'pyblake2; python_version<"3.6" and platform_python_implementation=="CPython"', + ], 'keyring': [ 'keyring', ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/helpers.py new/twine-1.13.0/tests/helpers.py --- old/twine-1.12.1/tests/helpers.py 2017-01-19 15:23:11.000000000 +0100 +++ new/twine-1.13.0/tests/helpers.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_check.py new/twine-1.13.0/tests/test_check.py --- old/twine-1.12.1/tests/test_check.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/tests/test_check.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -58,11 +58,13 @@ renderer = pretend.stub( render=pretend.call_recorder(lambda *a, **kw: "valid") ) - package = pretend.stub(metadata_dictionary=lambda: {"description": "blah"}) + package = pretend.stub(metadata_dictionary=lambda: { + "description": "blah", 'description_content_type': 'text/markdown', + }) output_stream = check.StringIO() warning_stream = "" - monkeypatch.setattr(check, "_RENDERERS", {"": renderer}) + monkeypatch.setattr(check, "_RENDERERS", {None: renderer}) monkeypatch.setattr(check, "_find_dists", lambda a: ["dist/dist.tar.gz"]) monkeypatch.setattr( check, @@ -81,15 +83,41 @@ ] +def test_check_no_description(monkeypatch, capsys): + package = pretend.stub(metadata_dictionary=lambda: { + 'description': None, 'description_content_type': None, + }) + + monkeypatch.setattr(check, "_find_dists", lambda a: ["dist/dist.tar.gz"]) + monkeypatch.setattr( + check, + "PackageFile", + pretend.stub(from_filename=lambda *a, **kw: package), + ) + + # used to crash with `AttributeError` + output_stream = check.StringIO() + check.check("dist/*", output_stream=output_stream) + assert output_stream.getvalue() == ( + 'Checking distribution dist/dist.tar.gz: ' + 'warning: `long_description_content_type` missing. ' + 'defaulting to `text/x-rst`.\n' + 'warning: `long_description` missing.\n' + 'Passed\n' + ) + + def test_check_failing_distribution(monkeypatch): renderer = pretend.stub( render=pretend.call_recorder(lambda *a, **kw: None) ) - package = pretend.stub(metadata_dictionary=lambda: {"description": "blah"}) + package = pretend.stub(metadata_dictionary=lambda: { + "description": "blah", "description_content_type": 'text/markdown', + }) output_stream = check.StringIO() warning_stream = "WARNING" - monkeypatch.setattr(check, "_RENDERERS", {"": renderer}) + monkeypatch.setattr(check, "_RENDERERS", {None: renderer}) monkeypatch.setattr(check, "_find_dists", lambda a: ["dist/dist.tar.gz"]) monkeypatch.setattr( check, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_cli.py new/twine-1.13.0/tests/test_cli.py --- old/twine-1.12.1/tests/test_cli.py 2017-01-19 15:23:11.000000000 +0100 +++ new/twine-1.13.0/tests/test_cli.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_main.py new/twine-1.13.0/tests/test_main.py --- old/twine-1.12.1/tests/test_main.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/tests/test_main.py 2019-02-13 21:35:39.000000000 +0100 @@ -2,7 +2,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_package.py new/twine-1.13.0/tests/test_package.py --- old/twine-1.12.1/tests/test_package.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/tests/test_package.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_repository.py new/twine-1.13.0/tests/test_repository.py --- old/twine-1.12.1/tests/test_repository.py 2018-04-28 13:17:37.000000000 +0200 +++ new/twine-1.13.0/tests/test_repository.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -17,6 +17,8 @@ from twine.utils import DEFAULT_REPOSITORY import pretend +import pytest +from contextlib import contextmanager def test_gpg_signature_structure_is_preserved(): @@ -140,3 +142,49 @@ ) assert repo.package_is_uploaded(package) is False + + [email protected]('disable_progress_bar', [ + True, + False +]) +def test_disable_progress_bar_is_forwarded_to_tqdm(monkeypatch, tmpdir, + disable_progress_bar): + """Test whether the disable flag is passed to tqdm + when the disable_progress_bar option is passed to the + repository + """ + @contextmanager + def progressbarstub(*args, **kwargs): + assert "disable" in kwargs + assert kwargs["disable"] == disable_progress_bar + yield + + monkeypatch.setattr(repository, "ProgressBar", progressbarstub) + repo = repository.Repository( + repository_url=DEFAULT_REPOSITORY, + username='username', + password='password', + disable_progress_bar=disable_progress_bar + ) + + repo.session = pretend.stub( + post=lambda url, data, allow_redirects, headers: response_with( + status_code=200) + ) + + fakefile = tmpdir.join('fake.whl') + fakefile.write('.') + + def dictfunc(): + return {"name": "fake"} + + package = pretend.stub( + safe_name='fake', + metadata=pretend.stub(version='2.12.0'), + basefilename="fake.whl", + filename=str(fakefile), + metadata_dictionary=dictfunc + ) + + repo.upload(package) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_settings.py new/twine-1.13.0/tests/test_settings.py --- old/twine-1.12.1/tests/test_settings.py 2018-05-18 19:14:50.000000000 +0200 +++ new/twine-1.13.0/tests/test_settings.py 2019-02-13 21:35:39.000000000 +0100 @@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -49,6 +49,7 @@ assert s.password == 'password' assert s.cacert is None assert s.client_cert is None + assert s.disable_progress_bar is False def test_identity_requires_sign(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_upload.py new/twine-1.13.0/tests/test_upload.py --- old/twine-1.12.1/tests/test_upload.py 2018-09-24 20:40:31.000000000 +0200 +++ new/twine-1.13.0/tests/test_upload.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -133,6 +133,20 @@ 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_nexus(monkeypatch): + # Nexus Repository Manager (https://www.sonatype.com/nexus-repository-oss) + # responds with 400 when the file already exists + response = pretend.stub( + status_code=400, + reason="Repository does not allow updating assets: pypi for url: " + "http://www.foo.bar") + + pkg = package.PackageFile.from_filename(WHEEL_FIXTURE, None) + assert upload.skip_upload(response=response, skip_existing=True, package=pkg) is True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_utils.py new/twine-1.13.0/tests/test_utils.py --- old/twine-1.12.1/tests/test_utils.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/tests/test_utils.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -126,6 +126,26 @@ } +def test_empty_userpass(tmpdir): + """ + Empty username and password may be supplied to suppress + prompts. See #426. + """ + pypirc = os.path.join(str(tmpdir), ".pypirc") + + with open(pypirc, "w") as fp: + fp.write(textwrap.dedent(""" + [pypi] + username= + password= + """)) + + config = utils.get_config(pypirc) + pypi = config['pypi'] + + assert pypi['username'] == pypi['password'] == '' + + def test_get_repository_config_missing(tmpdir): pypirc = os.path.join(str(tmpdir), ".pypirc") @@ -229,6 +249,45 @@ assert pw == 'entered pw' +def test_no_password_defers_to_prompt(monkeypatch): + monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw') + pw = utils.get_password('system', 'user', None, {'password': None}) + assert pw == 'entered pw' + + +def test_empty_password_bypasses_prompt(monkeypatch): + monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw') + pw = utils.get_password('system', 'user', None, {'password': ''}) + assert pw == '' + + +def test_get_username_and_password_keyring_overrides_prompt(monkeypatch): + import collections + Credential = collections.namedtuple('Credential', 'username password') + + class MockKeyring: + @staticmethod + def get_credential(system, user): + return Credential( + 'real_user', + 'real_user@{system} sekure pa55word'.format(**locals()) + ) + + @staticmethod + def get_password(system, user): + cred = MockKeyring.get_credential(system, user) + if user != cred.username: + raise RuntimeError("unexpected username") + return cred.password + + monkeypatch.setitem(sys.modules, 'keyring', MockKeyring) + + user = utils.get_username('system', None, {}) + assert user == 'real_user' + pw = utils.get_password('system', user, None, {}) + assert pw == 'real_user@system sekure pa55word' + + @pytest.fixture def keyring_missing(monkeypatch): """ @@ -238,10 +297,30 @@ @pytest.fixture +def keyring_missing_get_credentials(monkeypatch): + """ + Simulate older versions of keyring that do not have the + 'get_credentials' API. + """ + monkeypatch.delattr('keyring.backends.KeyringBackend', + 'get_credential', raising=False) + + [email protected] +def entered_username(monkeypatch): + monkeypatch.setattr(utils, 'input_func', lambda prompt: 'entered user') + + [email protected] def entered_password(monkeypatch): monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw') +def test_get_username_keyring_missing_get_credentials_prompts( + entered_username, keyring_missing_get_credentials): + assert utils.get_username('system', None, {}) == 'entered user' + + def test_get_password_keyring_missing_prompts( entered_password, keyring_missing): assert utils.get_password('system', 'user', None, {}) == 'entered pw' @@ -261,6 +340,28 @@ monkeypatch.setitem(sys.modules, 'keyring', FailKeyring()) [email protected] +def keyring_no_backends_get_credential(monkeypatch): + """ + Simulate that keyring has no available backends. When keyring + has no backends for the system, the backend will be a + fail.Keyring, which raises RuntimeError on get_password. + """ + class FailKeyring(object): + @staticmethod + def get_credential(system, username): + raise RuntimeError("fail!") + monkeypatch.setitem(sys.modules, 'keyring', FailKeyring()) + + +def test_get_username_runtime_error_suppressed( + entered_username, keyring_no_backends_get_credential, recwarn): + assert utils.get_username('system', None, {}) == 'entered user' + assert len(recwarn) == 1 + warning = recwarn.pop(UserWarning) + assert 'fail!' in str(warning) + + def test_get_password_runtime_error_suppressed( entered_password, keyring_no_backends, recwarn): assert utils.get_password('system', 'user', None, {}) == 'entered pw' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/tests/test_wheel.py new/twine-1.13.0/tests/test_wheel.py --- old/twine-1.12.1/tests/test_wheel.py 2017-05-17 13:50:28.000000000 +0200 +++ new/twine-1.13.0/tests/test_wheel.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/__init__.py new/twine-1.13.0/twine/__init__.py --- old/twine-1.12.1/twine/__init__.py 2018-09-24 20:40:31.000000000 +0200 +++ new/twine-1.13.0/twine/__init__.py 2019-02-13 22:37:01.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,7 @@ __summary__ = "Collection of utilities for publishing packages on PyPI" __uri__ = "https://twine.readthedocs.io/" -__version__ = "1.12.1" +__version__ = "1.13.0" __author__ = "Donald Stufft and individual contributors" __email__ = "[email protected]" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/__main__.py new/twine-1.13.0/twine/__main__.py --- old/twine-1.12.1/twine/__main__.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/__main__.py 2019-02-13 21:35:39.000000000 +0100 @@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -27,10 +27,7 @@ try: return dispatch(sys.argv[1:]) except (exceptions.TwineException, requests.exceptions.HTTPError) as exc: - return '{0}: {1}'.format( - exc.__class__.__name__, - exc.args[0], - ) + return '{}: {}'.format(exc.__class__.__name__, exc.args[0]) if __name__ == "__main__": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/cli.py new/twine-1.13.0/twine/cli.py --- old/twine-1.12.1/twine/cli.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/cli.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -29,7 +29,7 @@ def _registered_commands(group='twine.registered_commands'): registered_commands = pkg_resources.iter_entry_points(group=group) - return dict((c.name, c) for c in registered_commands) + return {c.name: c for c in registered_commands} def list_dependencies_and_versions(): @@ -44,7 +44,7 @@ def dep_versions(): return ', '.join( - '{0}: {1}'.format(*dependency) + '{}: {}'.format(*dependency) for dependency in list_dependencies_and_versions() ) @@ -55,8 +55,10 @@ parser.add_argument( "--version", action="version", - version="%(prog)s version {0} ({1})".format(twine.__version__, - dep_versions()), + version="%(prog)s version {} ({})".format( + twine.__version__, + dep_versions(), + ), ) parser.add_argument( "command", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/commands/__init__.py new/twine-1.13.0/twine/commands/__init__.py --- old/twine-1.12.1/twine/commands/__init__.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/commands/__init__.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/commands/check.py new/twine-1.13.0/twine/commands/check.py --- old/twine-1.12.1/twine/commands/check.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/commands/check.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -18,25 +18,18 @@ import cgi import re import sys +from io import StringIO -try: - from StringIO import StringIO -except ImportError: - from _io import StringIO - -import readme_renderer.markdown import readme_renderer.rst -import readme_renderer.txt from twine.commands import _find_dists from twine.package import PackageFile _RENDERERS = { None: readme_renderer.rst, # Default if description_content_type is None - "": readme_renderer.rst, # Default if description_content_type is None - "text/plain": readme_renderer.txt, + "text/plain": None, # Rendering cannot fail "text/x-rst": readme_renderer.rst, - "text/markdown": readme_renderer.markdown, + "text/markdown": None, # Rendering cannot fail } @@ -85,28 +78,37 @@ package = PackageFile.from_filename(filename, comment=None) metadata = package.metadata_dictionary() - content_type, parameters = cgi.parse_header( - metadata.get("description_content_type") or "" - ) - - # Get the appropriate renderer - renderer = _RENDERERS.get(content_type, readme_renderer.txt) - - # Actually render the given value - rendered = renderer.render( - metadata.get("description"), stream=stream, **parameters - ) + description = metadata["description"] + description_content_type = metadata["description_content_type"] - if rendered is None: - failure = True - output_stream.write("Failed\n") + if description_content_type is None: output_stream.write( - "The project's long_description has invalid markup which will " - "not be rendered on PyPI. The following syntax errors were " - "detected:\n%s" % stream + 'warning: `long_description_content_type` missing. ' + 'defaulting to `text/x-rst`.\n' ) - else: + description_content_type = 'text/x-rst' + + content_type, params = cgi.parse_header(description_content_type) + renderer = _RENDERERS.get(content_type, _RENDERERS[None]) + + if description in {None, 'UNKNOWN\n\n\n'}: + output_stream.write('warning: `long_description` missing.\n') output_stream.write("Passed\n") + else: + if ( + renderer + and renderer.render(description, stream=stream, **params) + is None + ): + failure = True + output_stream.write("Failed\n") + output_stream.write( + "The project's long_description has invalid markup which " + "will not be rendered on PyPI. The following syntax " + "errors were detected:\n%s" % stream + ) + else: + output_stream.write("Passed\n") return failure diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/commands/register.py new/twine-1.13.0/twine/commands/register.py --- old/twine-1.12.1/twine/commands/register.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/commands/register.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -24,12 +24,12 @@ def register(register_settings, package): repository_url = register_settings.repository_config['repository'] - print("Registering package to {0}".format(repository_url)) + print("Registering package to {}".format(repository_url)) repository = register_settings.create_repository() if not os.path.exists(package): raise exceptions.PackageNotFound( - '"{0}" does not exist on the file system.'.format(package) + '"{}" does not exist on the file system.'.format(package) ) resp = repository.register( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/commands/upload.py new/twine-1.13.0/twine/commands/upload.py --- old/twine-1.12.1/twine/commands/upload.py 2018-09-24 20:40:31.000000000 +0200 +++ new/twine-1.13.0/twine/commands/upload.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -26,10 +26,14 @@ def skip_upload(response, skip_existing, package): filename = package.basefilename - # NOTE(sigmavirus24): Old PyPI returns the first message while Warehouse - # returns the latter. This papers over the differences. - msg_400 = ('A file named "{0}" already exists for'.format(filename), - 'File already exists') + msg_400 = ( + # Old PyPI message: + 'A file named "{}" already exists for'.format(filename), + # Warehouse message: + 'File already exists', + # Nexus Repository OSS message: + 'Repository does not allow updating assets', + ) msg_403 = 'Not enough permissions to overwrite artifact' # NOTE(sigmavirus24): PyPI presently returns a 400 status code with the # error message in the reason attribute. Other implementations return a @@ -38,7 +42,7 @@ # 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. OR + # what we expect PyPI or Nexus OSS to return to us. OR # 2. c) The response status code is 403 AND the text matches what we # expect Artifactory to return to us. return (skip_existing and (response.status_code == 409 or @@ -51,21 +55,19 @@ dists = _find_dists(dists) # Determine if the user has passed in pre-signed distributions - signatures = dict( - (os.path.basename(d), d) for d in dists if d.endswith(".asc") - ) + signatures = {os.path.basename(d): d for d in dists if d.endswith(".asc")} uploads = [i for i in dists if not i.endswith(".asc")] upload_settings.check_repository_url() repository_url = upload_settings.repository_config['repository'] - print("Uploading distributions to {0}".format(repository_url)) + print("Uploading distributions to {}".format(repository_url)) repository = upload_settings.create_repository() for filename in uploads: package = PackageFile.from_filename(filename, upload_settings.comment) skip_message = ( - " Skipping {0} because it appears to already exist".format( + " Skipping {} because it appears to already exist".format( package.basefilename) ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/exceptions.py new/twine-1.13.0/twine/exceptions.py --- old/twine-1.12.1/twine/exceptions.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/exceptions.py 2019-02-13 21:35:39.000000000 +0100 @@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -50,10 +50,10 @@ @classmethod def from_args(cls, target_url, default_url, test_url): """Return an UploadToDeprecatedPyPIDetected instance.""" - return cls("You're trying to upload to the legacy PyPI site '{0}'. " + return cls("You're trying to upload to the legacy PyPI site '{}'. " "Uploading to those sites is deprecated. \n " "The new sites are pypi.org and test.pypi.org. Try using " - "{1} (or {2}) to upload your packages instead. " + "{} (or {}) to upload your packages instead. " "These are the default URLs for Twine now. \n More at " "https://packaging.python.org/guides/migrating-to-pypi-org/" " .".format(target_url, default_url, test_url) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/package.py new/twine-1.13.0/twine/package.py --- old/twine-1.12.1/twine/package.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/package.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -160,7 +160,7 @@ self.gpg_signature = (signature_filename, gpg.read()) def sign(self, sign_with, identity): - print("Signing {0}".format(self.basefilename)) + print("Signing {}".format(self.basefilename)) gpg_args = (sign_with, "--detach-sign") if identity: gpg_args += ("--local-user", identity) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/repository.py new/twine-1.13.0/twine/repository.py --- old/twine-1.12.1/twine/repository.py 2018-04-28 13:17:37.000000000 +0200 +++ new/twine-1.13.0/twine/repository.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -28,7 +28,7 @@ import twine -KEYWORDS_TO_NOT_FLATTEN = set(["gpg_signature", "content"]) +KEYWORDS_TO_NOT_FLATTEN = {"gpg_signature", "content"} LEGACY_PYPI = 'https://pypi.python.org/' LEGACY_TEST_PYPI = 'https://testpypi.python.org/' @@ -47,7 +47,8 @@ class Repository(object): - def __init__(self, repository_url, username, password): + def __init__(self, repository_url, username, password, + disable_progress_bar=False): self.url = repository_url self.session = requests.session() self.session.auth = (username, password) @@ -55,6 +56,7 @@ for scheme in ('http://', 'https://'): self.session.mount(scheme, self._make_adapter_with_retries()) self._releases_json_data = {} + self.disable_progress_bar = disable_progress_bar @staticmethod def _make_adapter_with_retries(): @@ -106,7 +108,7 @@ "protocol_version": "1", }) - print("Registering {0}".format(package.basefilename)) + print("Registering {}".format(package.basefilename)) data_to_send = self._convert_data_to_list_of_tuples(data) encoder = MultipartEncoder(data_to_send) @@ -130,7 +132,7 @@ data_to_send = self._convert_data_to_list_of_tuples(data) - print("Uploading {0}".format(package.basefilename)) + print("Uploading {}".format(package.basefilename)) with open(package.filename, "rb") as fp: data_to_send.append(( @@ -140,7 +142,8 @@ encoder = MultipartEncoder(data_to_send) with ProgressBar(total=encoder.len, unit='B', unit_scale=True, unit_divisor=1024, - miniters=1, file=sys.stdout) as bar: + miniters=1, file=sys.stdout, + disable=self.disable_progress_bar) as bar: monitor = MultipartEncoderMonitor( encoder, lambda monitor: bar.update_to(monitor.bytes_read) ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/settings.py new/twine-1.13.0/twine/settings.py --- old/twine-1.12.1/twine/settings.py 2018-05-18 19:14:50.000000000 +0200 +++ new/twine-1.13.0/twine/settings.py 2019-02-13 21:35:39.000000000 +0100 @@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -46,6 +46,7 @@ cacert=None, client_cert=None, repository_name='pypi', repository_url=None, verbose=False, + disable_progress_bar=False, **ignored_kwargs ): """Initialize our settings instance. @@ -95,10 +96,15 @@ will override the settings inferred from ``repository_name``. :param bool verbose: Show verbose output. + :param bool disable_progress_bar: + Disable the progress bar. + + This defaults to ``False`` """ self.config_file = config_file self.comment = comment self.verbose = verbose + self.disable_progress_bar = disable_progress_bar self.skip_existing = skip_existing self._handle_repository_options( repository_name=repository_name, repository_url=repository_url, @@ -206,6 +212,13 @@ action="store_true", help="Show verbose output." ) + parser.add_argument( + "--disable-progress-bar", + default=False, + required=False, + action="store_true", + help="Disable the progress bar." + ) @classmethod def from_argparse(cls, args): @@ -235,7 +248,11 @@ ) def _handle_authentication(self, username, password): - self.username = utils.get_username(username, self.repository_config) + self.username = utils.get_username( + self.repository_config['repository'], + username, + self.repository_config + ) self.password = utils.get_password( self.repository_config['repository'], self.username, @@ -272,6 +289,7 @@ self.repository_config['repository'], self.username, self.password, + self.disable_progress_bar ) repo.set_certificate_authority(self.cacert) repo.set_client_certificate(self.client_cert) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/utils.py new/twine-1.13.0/twine/utils.py --- old/twine-1.12.1/twine/utils.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/utils.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -35,6 +35,11 @@ except ImportError: from urllib.parse import urlparse, urlunparse +try: + import keyring # noqa +except ImportError: + pass + from twine import exceptions # Shim for raw_input in python3 @@ -110,7 +115,7 @@ } if repository_url and "://" not in repository_url: raise exceptions.UnreachableRepositoryURLDetected( - "Repository URL {0} has no protocol. Please add " + "Repository URL {} has no protocol. Please add " "'https://'. \n".format(repository_url)) try: return get_config(config_file)[repository] @@ -128,8 +133,8 @@ raise exceptions.InvalidConfiguration(msg) -_HOSTNAMES = set(["pypi.python.org", "testpypi.python.org", "upload.pypi.org", - "test.pypi.org"]) +_HOSTNAMES = {"pypi.python.org", "testpypi.python.org", "upload.pypi.org", + "test.pypi.org"} def normalize_repository_url(url): @@ -190,7 +195,7 @@ """ if cli_value is not None: return cli_value - elif config.get(key): + elif config.get(key) is not None: return config[key] elif prompt_strategy: return prompt_strategy() @@ -198,6 +203,23 @@ return None +def get_username_from_keyring(system): + if 'keyring' not in sys.modules: + return + + try: + getter = sys.modules['keyring'].get_credential + except AttributeError: + return None + + try: + creds = getter(system, None) + if creds: + return creds.username + except Exception as exc: + warnings.warn(str(exc)) + + def password_prompt(prompt_text): # Always expects unicode for our own sanity prompt = prompt_text # Workaround for https://github.com/pypa/twine/issues/116 @@ -211,12 +233,18 @@ return try: - import keyring - return keyring.get_password(system, username) + return sys.modules['keyring'].get_password(system, username) except Exception as exc: warnings.warn(str(exc)) +def username_from_keyring_or_prompt(system): + return ( + get_username_from_keyring(system) + or input_func('Enter your username: ') + ) + + def password_from_keyring_or_prompt(system, username): return ( get_password_from_keyring(system, username) @@ -224,11 +252,18 @@ ) -get_username = functools.partial( - get_userpass_value, - key='username', - prompt_strategy=functools.partial(input_func, 'Enter your username: '), -) +def get_username(system, cli_value, config): + return get_userpass_value( + cli_value, + config, + key='username', + prompt_strategy=functools.partial( + username_from_keyring_or_prompt, + system, + ), + ) + + get_cacert = functools.partial( get_userpass_value, key='ca_cert', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine/wheel.py new/twine-1.13.0/twine/wheel.py --- old/twine-1.12.1/twine/wheel.py 2018-09-22 15:31:35.000000000 +0200 +++ new/twine-1.13.0/twine/wheel.py 2019-02-13 21:35:39.000000000 +0100 @@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -17,11 +17,7 @@ import os import re import zipfile - -try: - from StringIO import StringIO -except ImportError: - from _io import StringIO +from io import StringIO from pkginfo import distribution from pkginfo.distribution import Distribution diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine.egg-info/PKG-INFO new/twine-1.13.0/twine.egg-info/PKG-INFO --- old/twine-1.12.1/twine.egg-info/PKG-INFO 2018-09-24 20:41:42.000000000 +0200 +++ new/twine-1.13.0/twine.egg-info/PKG-INFO 2019-02-13 22:38:54.000000000 +0100 @@ -1,15 +1,19 @@ Metadata-Version: 2.1 Name: twine -Version: 1.12.1 +Version: 1.13.0 Summary: Collection of utilities for publishing packages on PyPI Home-page: https://twine.readthedocs.io/ Author: Donald Stufft and individual contributors Author-email: [email protected] License: Apache License, Version 2.0 -Project-URL: Twine source, https://github.com/pypa/twine/ Project-URL: Packaging tutorial, https://packaging.python.org/tutorials/distributing-packages/ +Project-URL: Travis CI, https://travis-ci.org/pypa/twine Project-URL: Twine documentation, https://twine.readthedocs.io/en/latest/ -Description: twine +Project-URL: Twine source, https://github.com/pypa/twine/ +Description: .. image:: https://img.shields.io/travis/pypa/twine/master.svg?label=travis-ci + :target: https://travis-ci.org/pypa/twine + + twine ===== .. rtd-inclusion-marker-do-not-remove @@ -148,7 +152,7 @@ Disabling Keyring ^^^^^^^^^^^^^^^^^ - In some cases, the presence of keyring may be problemmatic. To disable + In some cases, the presence of keyring may be problematic. To disable keyring and defer to a prompt for passwords, uninstall ``keyring`` or if that's not an option, you can also configure keyring to be disabled. @@ -171,6 +175,7 @@ [-s] [--sign-with SIGN_WITH] [-i IDENTITY] [-u USERNAME] [-p PASSWORD] [-c COMMENT] [--config-file CONFIG_FILE] [--skip-existing] [--cert path] [--client-cert path] + [--verbose] [--disable-progress-bar] dist [dist ...] positional arguments: @@ -215,6 +220,9 @@ --client-cert path Path to SSL client certificate, a single file containing the private key and the certificate in PEM format. + --verbose Show verbose output. + --disable-progress-bar + Disable the progress bar. ``twine check`` ^^^^^^^^^^^^^^^ @@ -357,7 +365,9 @@ Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy -Provides-Extra: keyring +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* Provides-Extra: with-blake2 +Provides-Extra: keyring diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/twine-1.12.1/twine.egg-info/requires.txt new/twine-1.13.0/twine.egg-info/requires.txt --- old/twine-1.12.1/twine.egg-info/requires.txt 2018-09-24 20:41:42.000000000 +0200 +++ new/twine-1.13.0/twine.egg-info/requires.txt 2019-02-13 22:38:54.000000000 +0100 @@ -1,7 +1,7 @@ pkginfo>=1.4.2 readme_renderer>=21.0 requests!=2.15,!=2.16,>=2.5.0 -requests-toolbelt>=0.8.0 +requests-toolbelt!=0.9.0,>=0.8.0 setuptools>=0.7.0 tqdm>=4.14 @@ -9,4 +9,6 @@ keyring [with-blake2] + +[with-blake2:python_version < "3.6" and platform_python_implementation == "CPython"] pyblake2
