From 6018c11036ab3b7252afd78cbc5a05493506f291 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Sun, 6 Oct 2019 17:48:00 -0400 Subject: [PATCH 01/14] Add helpful error message for incorrect repository URL Signed-off-by: Aditya Saky --- twine/utils.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/twine/utils.py b/twine/utils.py index 1fd30ca7..581fdaa1 100644 --- a/twine/utils.py +++ b/twine/utils.py @@ -145,6 +145,15 @@ def check_status_code(response, verbose): "(or https://test.pypi.org/legacy/) to upload your packages " "instead. These are the default URLs for Twine now. More at " "https://packaging.python.org/guides/migrating-to-pypi-org/ ") + if (response.status_code == 405 and + response.url.startswith(("https://pypi.org", + "https://test.pypi.org"))): + print("You probably want one of these two URLs: {} or {}. Check {} for" + " more information.".format( + "https://pypi.org/legacy/", + "https://test.pypi.org/legacy/", + "https://warehouse.readthedocs.io/api-reference/legacy/" + "#upload-api")) try: response.raise_for_status() except HTTPError as err: From a7780bf9e004ea5d724a4f89bfa17972e94f5b73 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Mon, 7 Oct 2019 07:43:38 -0400 Subject: [PATCH 02/14] Update 405 check - change URL test, error message Signed-off-by: Aditya Saky --- twine/utils.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/twine/utils.py b/twine/utils.py index 581fdaa1..e2c0da05 100644 --- a/twine/utils.py +++ b/twine/utils.py @@ -145,15 +145,9 @@ def check_status_code(response, verbose): "(or https://test.pypi.org/legacy/) to upload your packages " "instead. These are the default URLs for Twine now. More at " "https://packaging.python.org/guides/migrating-to-pypi-org/ ") - if (response.status_code == 405 and - response.url.startswith(("https://pypi.org", - "https://test.pypi.org"))): - print("You probably want one of these two URLs: {} or {}. Check {} for" - " more information.".format( - "https://pypi.org/legacy/", - "https://test.pypi.org/legacy/", - "https://warehouse.readthedocs.io/api-reference/legacy/" - "#upload-api")) + elif response.status_code == 405 and "pypi.org" in response.url: + print(f"You probably want one of these two URLs: {DEFAULT_REPOSITORY} " + f"or {TEST_REPOSITORY}.") try: response.raise_for_status() except HTTPError as err: From ec53ae82e065cf60622e70baf9f842cf9ccdf713 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Mon, 7 Oct 2019 19:21:12 -0400 Subject: [PATCH 03/14] Move check_status_code to commands/upload; add corresponding test Signed-off-by: Aditya Saky --- tests/test_upload.py | 19 ++++++++++++++++++ twine/commands/upload.py | 42 ++++++++++++++++++++++++++++++++++++++-- twine/utils.py | 32 ------------------------------ 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index 396a4aaf..74af8e4f 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -27,6 +27,8 @@ NEW_SDIST_FIXTURE = 'tests/fixtures/twine-1.6.5.tar.gz' NEW_WHEEL_FIXTURE = 'tests/fixtures/twine-1.6.5-py2.py3-none-any.whl' NEW_RELEASE_URL = 'https://pypi.org/project/twine/1.6.5/' +DEFAULT_REPOSITORY = "https://upload.pypi.org/legacy/" +TEST_REPOSITORY = "https://test.pypi.org/legacy/" def test_successful_upload(make_settings, capsys): @@ -285,3 +287,20 @@ def none_upload(*args, **settings_kwargs): assert "pypipassword" == upload_settings.password assert "pypiuser" == upload_settings.username assert "/foo/bar.crt" == upload_settings.cacert + + +def test_check_status_code(make_settings, capsys): + upload_settings = make_settings() + + # override default upload_settings + upload_settings.repository_config['repository'] = \ + "https://upload.pypi.org" + + with pytest.raises(HTTPError): + upload.upload(upload_settings, [ + WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE + ]) + + captured = capsys.readouterr() + assert captured.out.count(DEFAULT_REPOSITORY) == 1 + assert captured.out.count(TEST_REPOSITORY) == 1 diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 8057dca9..69937c76 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -18,7 +18,12 @@ from twine.package import PackageFile from twine import exceptions from twine import settings -from twine import utils + +from requests.exceptions import HTTPError + + +DEFAULT_REPOSITORY = "https://upload.pypi.org/legacy/" +TEST_REPOSITORY = "https://test.pypi.org/legacy/" def skip_upload(response, skip_existing, package): @@ -48,6 +53,39 @@ def skip_upload(response, skip_existing, package): (response.status_code == 403 and msg_403 in response.text))) +def check_status_code(response, verbose): + """ + Additional safety net to catch response code 410 in case the + UploadToDeprecatedPyPIDetected exception breaks. + Also includes a check for response code 405 and prints helpful error + message guiding users to the right repository endpoints. + """ + if (response.status_code == 410 and + response.url.startswith(("https://pypi.python.org", + "https://testpypi.python.org"))): + print("It appears you're uploading to pypi.python.org (or " + "testpypi.python.org). You've received a 410 error response. " + "Uploading to those sites is deprecated. The new sites are " + "pypi.org and test.pypi.org. Try using " + "https://upload.pypi.org/legacy/ " + "(or https://test.pypi.org/legacy/) to upload your packages " + "instead. These are the default URLs for Twine now. More at " + "https://packaging.python.org/guides/migrating-to-pypi-org/ ") + elif response.status_code == 405 and "pypi.org" in response.url: + print(f"You probably want one of these two URLs: {DEFAULT_REPOSITORY} " + f"or {TEST_REPOSITORY}.") + try: + response.raise_for_status() + except HTTPError as err: + if response.text: + if verbose: + print('Content received from server:\n{}'.format( + response.text)) + else: + print('NOTE: Try --verbose to see response content.') + raise err + + def upload(upload_settings, dists): dists = _find_dists(dists) @@ -99,7 +137,7 @@ def upload(upload_settings, dists): print(skip_message) continue - utils.check_status_code(resp, upload_settings.verbose) + check_status_code(resp, upload_settings.verbose) uploaded_packages.append(package) diff --git a/twine/utils.py b/twine/utils.py index e2c0da05..986681b3 100644 --- a/twine/utils.py +++ b/twine/utils.py @@ -22,7 +22,6 @@ import configparser from urllib.parse import urlparse, urlunparse -from requests.exceptions import HTTPError try: import keyring # noqa @@ -129,37 +128,6 @@ def normalize_repository_url(url): return urlunparse(parsed) -def check_status_code(response, verbose): - """ - Shouldn't happen, thanks to the UploadToDeprecatedPyPIDetected - exception, but this is in case that breaks and it does. - """ - if (response.status_code == 410 and - response.url.startswith(("https://pypi.python.org", - "https://testpypi.python.org"))): - print("It appears you're uploading to pypi.python.org (or " - "testpypi.python.org). You've received a 410 error response. " - "Uploading to those sites is deprecated. The new sites are " - "pypi.org and test.pypi.org. Try using " - "https://upload.pypi.org/legacy/ " - "(or https://test.pypi.org/legacy/) to upload your packages " - "instead. These are the default URLs for Twine now. More at " - "https://packaging.python.org/guides/migrating-to-pypi-org/ ") - elif response.status_code == 405 and "pypi.org" in response.url: - print(f"You probably want one of these two URLs: {DEFAULT_REPOSITORY} " - f"or {TEST_REPOSITORY}.") - try: - response.raise_for_status() - except HTTPError as err: - if response.text: - if verbose: - print('Content received from server:\n{}'.format( - response.text)) - else: - print('NOTE: Try --verbose to see response content.') - raise err - - def get_userpass_value(cli_value, config, key, prompt_strategy=None): """Gets the username / password from config. From ea8d01050410e3e55e8015627be05043b7d3fcb2 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Mon, 7 Oct 2019 20:39:24 -0400 Subject: [PATCH 04/14] Import repository constants from utils; use them in 410 check; update test name and override comment Signed-off-by: Aditya Saky --- tests/test_upload.py | 7 +++---- twine/commands/upload.py | 9 +++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index 74af8e4f..9c549667 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -18,6 +18,7 @@ from twine.commands import upload from twine import package, cli, exceptions import twine +from twine.utils import DEFAULT_REPOSITORY, TEST_REPOSITORY import helpers @@ -27,8 +28,6 @@ NEW_SDIST_FIXTURE = 'tests/fixtures/twine-1.6.5.tar.gz' NEW_WHEEL_FIXTURE = 'tests/fixtures/twine-1.6.5-py2.py3-none-any.whl' NEW_RELEASE_URL = 'https://pypi.org/project/twine/1.6.5/' -DEFAULT_REPOSITORY = "https://upload.pypi.org/legacy/" -TEST_REPOSITORY = "https://test.pypi.org/legacy/" def test_successful_upload(make_settings, capsys): @@ -289,10 +288,10 @@ def none_upload(*args, **settings_kwargs): assert "/foo/bar.crt" == upload_settings.cacert -def test_check_status_code(make_settings, capsys): +def test_check_status_code_for_wrong_repo_url(make_settings, capsys): upload_settings = make_settings() - # override default upload_settings + # override defaults to use incorrect URL upload_settings.repository_config['repository'] = \ "https://upload.pypi.org" diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 69937c76..0664c835 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -18,14 +18,11 @@ from twine.package import PackageFile from twine import exceptions from twine import settings +from twine.utils import DEFAULT_REPOSITORY, TEST_REPOSITORY from requests.exceptions import HTTPError -DEFAULT_REPOSITORY = "https://upload.pypi.org/legacy/" -TEST_REPOSITORY = "https://test.pypi.org/legacy/" - - def skip_upload(response, skip_existing, package): filename = package.basefilename msg_400 = ( @@ -67,8 +64,8 @@ def check_status_code(response, verbose): "testpypi.python.org). You've received a 410 error response. " "Uploading to those sites is deprecated. The new sites are " "pypi.org and test.pypi.org. Try using " - "https://upload.pypi.org/legacy/ " - "(or https://test.pypi.org/legacy/) to upload your packages " + f"{DEFAULT_REPOSITORY} " + f"(or {TEST_REPOSITORY}) to upload your packages " "instead. These are the default URLs for Twine now. More at " "https://packaging.python.org/guides/migrating-to-pypi-org/ ") elif response.status_code == 405 and "pypi.org" in response.url: From d2cc71d6ba12adc74f799c46e264afb7329f71e6 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Mon, 7 Oct 2019 21:05:08 -0400 Subject: [PATCH 05/14] Add pytest.mark.parametrize to try both upload.pypi and test.pypi as repository URLs Signed-off-by: Aditya Saky --- tests/test_upload.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index 9c549667..b15d971c 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -288,12 +288,15 @@ def none_upload(*args, **settings_kwargs): assert "/foo/bar.crt" == upload_settings.cacert -def test_check_status_code_for_wrong_repo_url(make_settings, capsys): +@pytest.mark.parametrize('repo_url', [ + "https://upload.pypi.org/", + "https://test.pypi.org/" +]) +def test_check_status_code_for_wrong_repo_url(repo_url, make_settings, capsys): upload_settings = make_settings() # override defaults to use incorrect URL - upload_settings.repository_config['repository'] = \ - "https://upload.pypi.org" + upload_settings.repository_config['repository'] = repo_url with pytest.raises(HTTPError): upload.upload(upload_settings, [ From a31ba7bb8b130537124b850bf873027333b98d28 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Mon, 7 Oct 2019 21:15:58 -0400 Subject: [PATCH 06/14] Add a line pointing users to --repository-url value as source of error Signed-off-by: Aditya Saky --- twine/commands/upload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 0664c835..68de864c 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -70,7 +70,7 @@ def check_status_code(response, verbose): "https://packaging.python.org/guides/migrating-to-pypi-org/ ") elif response.status_code == 405 and "pypi.org" in response.url: print(f"You probably want one of these two URLs: {DEFAULT_REPOSITORY} " - f"or {TEST_REPOSITORY}.") + f"or {TEST_REPOSITORY}. Check your --repository-url value.") try: response.raise_for_status() except HTTPError as err: From 9068268664de8b251bfc14d004a205461fa88152 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Sat, 12 Oct 2019 13:51:59 -0400 Subject: [PATCH 07/14] Add exception for E405; add test for E410 Signed-off-by: Aditya Saky --- tests/test_upload.py | 27 ++++++++++++++++++++------- twine/commands/upload.py | 28 ++++++++++++++++++---------- twine/exceptions.py | 8 ++++++++ 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index b15d971c..e72f05e3 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -18,7 +18,8 @@ from twine.commands import upload from twine import package, cli, exceptions import twine -from twine.utils import DEFAULT_REPOSITORY, TEST_REPOSITORY +from twine.exceptions import PyPIMethodNotAllowed, \ + UploadToDeprecatedPyPIDetected import helpers @@ -290,19 +291,31 @@ def none_upload(*args, **settings_kwargs): @pytest.mark.parametrize('repo_url', [ "https://upload.pypi.org/", - "https://test.pypi.org/" + "https://test.pypi.org/", + "https://pypi.org/" ]) -def test_check_status_code_for_wrong_repo_url(repo_url, make_settings, capsys): +def test_check_status_code_for_wrong_repo_url(repo_url, make_settings): upload_settings = make_settings() # override defaults to use incorrect URL upload_settings.repository_config['repository'] = repo_url - with pytest.raises(HTTPError): + with pytest.raises(PyPIMethodNotAllowed): upload.upload(upload_settings, [ WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE ]) - captured = capsys.readouterr() - assert captured.out.count(DEFAULT_REPOSITORY) == 1 - assert captured.out.count(TEST_REPOSITORY) == 1 + +@pytest.mark.parametrize('repo_url', [ + "https://pypi.python.org", + "https://testpypi.python.org" +]) +def test_check_status_code_for_deprecated_pypi_url(repo_url): + response = pretend.stub( + status_code=410, + url=repo_url + ) + + # value of Verbose doesn't matter for this check + with pytest.raises(UploadToDeprecatedPyPIDetected): + upload.check_status_code(response, False) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 68de864c..001d5f79 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -60,17 +60,25 @@ def check_status_code(response, verbose): if (response.status_code == 410 and response.url.startswith(("https://pypi.python.org", "https://testpypi.python.org"))): - print("It appears you're uploading to pypi.python.org (or " - "testpypi.python.org). You've received a 410 error response. " - "Uploading to those sites is deprecated. The new sites are " - "pypi.org and test.pypi.org. Try using " - f"{DEFAULT_REPOSITORY} " - f"(or {TEST_REPOSITORY}) to upload your packages " - "instead. These are the default URLs for Twine now. More at " - "https://packaging.python.org/guides/migrating-to-pypi-org/ ") + raise exceptions.\ + UploadToDeprecatedPyPIDetected(f"It appears you're uploading to " + f"pypi.python.org (or " + f"testpypi.python.org). You've " + f"received a 410 error response. " + f"Uploading to those sites is " + f"deprecated. The new sites are " + f"pypi.org and test.pypi.org. Try " + f"using {DEFAULT_REPOSITORY} (or " + f"{TEST_REPOSITORY}) to upload your" + f" packages instead. These are the " + f"default URLs for Twine now. More " + f"at https://packaging.python.org/" + f"guides/migrating-to-pypi-org/.") elif response.status_code == 405 and "pypi.org" in response.url: - print(f"You probably want one of these two URLs: {DEFAULT_REPOSITORY} " - f"or {TEST_REPOSITORY}. Check your --repository-url value.") + raise exceptions.PyPIMethodNotAllowed(f"You probably want one of these" + f"two URLs: {DEFAULT_REPOSITORY}" + f"or {TEST_REPOSITORY}. Check " + f"your --repository-url value.") try: response.raise_for_status() except HTTPError as err: diff --git a/twine/exceptions.py b/twine/exceptions.py index 47a12ee6..91013515 100644 --- a/twine/exceptions.py +++ b/twine/exceptions.py @@ -101,3 +101,11 @@ class InvalidDistribution(TwineException): """Raised when a distribution is invalid.""" pass + + +class PyPIMethodNotAllowed(TwineException): + """Raised when --repository-url contains pypi.org but the upload + method is not supported. + """ + + pass From 1a9d5e0d1cf94cbb6176a27de505bf8c0b3bb50f Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Sun, 13 Oct 2019 12:19:33 -0400 Subject: [PATCH 08/14] Fix formatting; make 405 error message more descriptive Signed-off-by: Aditya Saky --- tests/test_upload.py | 8 +++++--- twine/commands/upload.py | 31 +++++++++++++------------------ twine/exceptions.py | 7 ++++--- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index e72f05e3..60eb7392 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -18,8 +18,10 @@ from twine.commands import upload from twine import package, cli, exceptions import twine -from twine.exceptions import PyPIMethodNotAllowed, \ - UploadToDeprecatedPyPIDetected +from twine.exceptions import ( + InvalidPyPIUploadURL, + UploadToDeprecatedPyPIDetected, +) import helpers @@ -300,7 +302,7 @@ def test_check_status_code_for_wrong_repo_url(repo_url, make_settings): # override defaults to use incorrect URL upload_settings.repository_config['repository'] = repo_url - with pytest.raises(PyPIMethodNotAllowed): + with pytest.raises(InvalidPyPIUploadURL): upload.upload(upload_settings, [ WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE ]) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 001d5f79..207acb6c 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -60,25 +60,20 @@ def check_status_code(response, verbose): if (response.status_code == 410 and response.url.startswith(("https://pypi.python.org", "https://testpypi.python.org"))): - raise exceptions.\ - UploadToDeprecatedPyPIDetected(f"It appears you're uploading to " - f"pypi.python.org (or " - f"testpypi.python.org). You've " - f"received a 410 error response. " - f"Uploading to those sites is " - f"deprecated. The new sites are " - f"pypi.org and test.pypi.org. Try " - f"using {DEFAULT_REPOSITORY} (or " - f"{TEST_REPOSITORY}) to upload your" - f" packages instead. These are the " - f"default URLs for Twine now. More " - f"at https://packaging.python.org/" - f"guides/migrating-to-pypi-org/.") + raise exceptions.UploadToDeprecatedPyPIDetected( + f"It appears you're uploading to pypi.python.org (or " + f"testpypi.python.org). You've received a 410 error response. " + f"Uploading to those sites is deprecated. The new sites are " + f"pypi.org and test.pypi.org. Try using {DEFAULT_REPOSITORY} (or " + f"{TEST_REPOSITORY}) to upload your packages instead. These are " + f"the default URLs for Twine now. More at " + f"https://packaging.python.org/guides/migrating-to-pypi-org/.") elif response.status_code == 405 and "pypi.org" in response.url: - raise exceptions.PyPIMethodNotAllowed(f"You probably want one of these" - f"two URLs: {DEFAULT_REPOSITORY}" - f"or {TEST_REPOSITORY}. Check " - f"your --repository-url value.") + raise exceptions.InvalidPyPIUploadURL( + f"It appears you're trying to upload to pypi.org but have an " + f"invalid URL. You probably want one of these two URLs: " + f"{DEFAULT_REPOSITORY} or {TEST_REPOSITORY}. Check your " + f"--repository-url value.") try: response.raise_for_status() except HTTPError as err: diff --git a/twine/exceptions.py b/twine/exceptions.py index 91013515..59e978ea 100644 --- a/twine/exceptions.py +++ b/twine/exceptions.py @@ -103,9 +103,10 @@ class InvalidDistribution(TwineException): pass -class PyPIMethodNotAllowed(TwineException): - """Raised when --repository-url contains pypi.org but the upload - method is not supported. +class InvalidPyPIUploadURL(TwineException): + """Repository configuration tries to use PyPI with an incorrect URL. + + For example, https://pypi.org instead of https://upload.pypi.org/legacy. """ pass From cf837a988ad00546122a7bf4e0a1de4d82621dcc Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Sun, 13 Oct 2019 14:56:09 -0400 Subject: [PATCH 09/14] Update E410 check for URL Signed-off-by: Aditya Saky --- twine/commands/upload.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 207acb6c..5a6b9631 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -57,9 +57,7 @@ def check_status_code(response, verbose): Also includes a check for response code 405 and prints helpful error message guiding users to the right repository endpoints. """ - if (response.status_code == 410 and - response.url.startswith(("https://pypi.python.org", - "https://testpypi.python.org"))): + if response.status_code == 410 and "pypi.python.org" in response.url: raise exceptions.UploadToDeprecatedPyPIDetected( f"It appears you're uploading to pypi.python.org (or " f"testpypi.python.org). You've received a 410 error response. " From 751e7ed477dca1b9709b88541d4dd02767690126 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Sun, 27 Oct 2019 23:22:03 -0400 Subject: [PATCH 10/14] Address review -import modules instead of specific items Signed-off-by: Aditya Saky --- tests/test_upload.py | 8 ++------ twine/commands/upload.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index 60eb7392..7986e998 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -18,10 +18,6 @@ from twine.commands import upload from twine import package, cli, exceptions import twine -from twine.exceptions import ( - InvalidPyPIUploadURL, - UploadToDeprecatedPyPIDetected, -) import helpers @@ -302,7 +298,7 @@ def test_check_status_code_for_wrong_repo_url(repo_url, make_settings): # override defaults to use incorrect URL upload_settings.repository_config['repository'] = repo_url - with pytest.raises(InvalidPyPIUploadURL): + with pytest.raises(twine.exceptions.InvalidPyPIUploadURL): upload.upload(upload_settings, [ WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE ]) @@ -319,5 +315,5 @@ def test_check_status_code_for_deprecated_pypi_url(repo_url): ) # value of Verbose doesn't matter for this check - with pytest.raises(UploadToDeprecatedPyPIDetected): + with pytest.raises(twine.exceptions.UploadToDeprecatedPyPIDetected): upload.check_status_code(response, False) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 5a6b9631..5550ef32 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -18,9 +18,9 @@ from twine.package import PackageFile from twine import exceptions from twine import settings -from twine.utils import DEFAULT_REPOSITORY, TEST_REPOSITORY +from twine import utils -from requests.exceptions import HTTPError +import requests def skip_upload(response, skip_existing, package): @@ -62,19 +62,19 @@ def check_status_code(response, verbose): f"It appears you're uploading to pypi.python.org (or " f"testpypi.python.org). You've received a 410 error response. " f"Uploading to those sites is deprecated. The new sites are " - f"pypi.org and test.pypi.org. Try using {DEFAULT_REPOSITORY} (or " - f"{TEST_REPOSITORY}) to upload your packages instead. These are " - f"the default URLs for Twine now. More at " + f"pypi.org and test.pypi.org. Try using {utils.DEFAULT_REPOSITORY} " + f"(or {utils.TEST_REPOSITORY}) to upload your packages instead. " + f"These are the default URLs for Twine now. More at " f"https://packaging.python.org/guides/migrating-to-pypi-org/.") elif response.status_code == 405 and "pypi.org" in response.url: raise exceptions.InvalidPyPIUploadURL( f"It appears you're trying to upload to pypi.org but have an " f"invalid URL. You probably want one of these two URLs: " - f"{DEFAULT_REPOSITORY} or {TEST_REPOSITORY}. Check your " - f"--repository-url value.") + f"{utils.DEFAULT_REPOSITORY} or {utils.TEST_REPOSITORY}. Check your" + f" --repository-url value.") try: response.raise_for_status() - except HTTPError as err: + except requests.HTTPError as err: if response.text: if verbose: print('Content received from server:\n{}'.format( From 5df08cb4dcaf8bd929d81ca40e1cf6c5d977f900 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Sun, 27 Oct 2019 23:25:56 -0400 Subject: [PATCH 11/14] Address review - docstring PEP257 compliance Signed-off-by: Aditya Saky --- twine/commands/upload.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 5550ef32..ab2ee66a 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -51,9 +51,9 @@ def skip_upload(response, skip_existing, package): def check_status_code(response, verbose): - """ - Additional safety net to catch response code 410 in case the + """Additional safety net to catch response code 410 in case the UploadToDeprecatedPyPIDetected exception breaks. + Also includes a check for response code 405 and prints helpful error message guiding users to the right repository endpoints. """ From 05d3783ce890d6762645d24f5b3997a0d9832d1d Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Sun, 27 Oct 2019 23:31:27 -0400 Subject: [PATCH 12/14] Linter - fix line lengths Signed-off-by: Aditya Saky --- twine/commands/upload.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index ab2ee66a..1a43d18c 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -62,16 +62,16 @@ def check_status_code(response, verbose): f"It appears you're uploading to pypi.python.org (or " f"testpypi.python.org). You've received a 410 error response. " f"Uploading to those sites is deprecated. The new sites are " - f"pypi.org and test.pypi.org. Try using {utils.DEFAULT_REPOSITORY} " - f"(or {utils.TEST_REPOSITORY}) to upload your packages instead. " + f"pypi.org and test.pypi.org. Try using {utils.DEFAULT_REPOSITORY}" + f" (or {utils.TEST_REPOSITORY}) to upload your packages instead. " f"These are the default URLs for Twine now. More at " f"https://packaging.python.org/guides/migrating-to-pypi-org/.") elif response.status_code == 405 and "pypi.org" in response.url: raise exceptions.InvalidPyPIUploadURL( f"It appears you're trying to upload to pypi.org but have an " f"invalid URL. You probably want one of these two URLs: " - f"{utils.DEFAULT_REPOSITORY} or {utils.TEST_REPOSITORY}. Check your" - f" --repository-url value.") + f"{utils.DEFAULT_REPOSITORY} or {utils.TEST_REPOSITORY}. Check " + f"your --repository-url value.") try: response.raise_for_status() except requests.HTTPError as err: From 98c0d30d5961b461b261be1d9033c44a9f982924 Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Mon, 28 Oct 2019 09:00:00 -0400 Subject: [PATCH 13/14] Address review - PEP257, style changes Signed-off-by: Aditya Saky --- tests/test_upload.py | 4 ++-- twine/commands/upload.py | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index 7986e998..a73bb568 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -298,7 +298,7 @@ def test_check_status_code_for_wrong_repo_url(repo_url, make_settings): # override defaults to use incorrect URL upload_settings.repository_config['repository'] = repo_url - with pytest.raises(twine.exceptions.InvalidPyPIUploadURL): + with pytest.raises(exceptions.InvalidPyPIUploadURL): upload.upload(upload_settings, [ WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE ]) @@ -315,5 +315,5 @@ def test_check_status_code_for_deprecated_pypi_url(repo_url): ) # value of Verbose doesn't matter for this check - with pytest.raises(twine.exceptions.UploadToDeprecatedPyPIDetected): + with pytest.raises(exceptions.UploadToDeprecatedPyPIDetected): upload.check_status_code(response, False) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 1a43d18c..78ef8478 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -51,11 +51,11 @@ def skip_upload(response, skip_existing, package): def check_status_code(response, verbose): - """Additional safety net to catch response code 410 in case the - UploadToDeprecatedPyPIDetected exception breaks. + """Generate a helpful message based on the response from the repository. - Also includes a check for response code 405 and prints helpful error - message guiding users to the right repository endpoints. + Raise a custom exception for recognized errors. Otherwise, print the + response content (based on the verbose option) before re-raising the + HTTPError. """ if response.status_code == 410 and "pypi.python.org" in response.url: raise exceptions.UploadToDeprecatedPyPIDetected( @@ -72,6 +72,7 @@ def check_status_code(response, verbose): f"invalid URL. You probably want one of these two URLs: " f"{utils.DEFAULT_REPOSITORY} or {utils.TEST_REPOSITORY}. Check " f"your --repository-url value.") + try: response.raise_for_status() except requests.HTTPError as err: From 360eb5a5e50bd6f225c932b2c91a12bf32ec055c Mon Sep 17 00:00:00 2001 From: Aditya Saky Date: Mon, 28 Oct 2019 09:31:53 -0400 Subject: [PATCH 14/14] Move check_status_code back to utils; move tests Signed-off-by: Aditya Saky --- tests/test_upload.py | 17 +---------------- tests/test_utils.py | 18 +++++++++++++++++- twine/commands/upload.py | 39 +-------------------------------------- twine/utils.py | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/tests/test_upload.py b/tests/test_upload.py index a73bb568..cc68ba9b 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -298,22 +298,7 @@ def test_check_status_code_for_wrong_repo_url(repo_url, make_settings): # override defaults to use incorrect URL upload_settings.repository_config['repository'] = repo_url - with pytest.raises(exceptions.InvalidPyPIUploadURL): + with pytest.raises(twine.exceptions.InvalidPyPIUploadURL): upload.upload(upload_settings, [ WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE ]) - - -@pytest.mark.parametrize('repo_url', [ - "https://pypi.python.org", - "https://testpypi.python.org" -]) -def test_check_status_code_for_deprecated_pypi_url(repo_url): - response = pretend.stub( - status_code=410, - url=repo_url - ) - - # value of Verbose doesn't matter for this check - with pytest.raises(exceptions.UploadToDeprecatedPyPIDetected): - upload.check_status_code(response, False) diff --git a/tests/test_utils.py b/tests/test_utils.py index a76d36b5..dd33787e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -16,8 +16,9 @@ import textwrap import pytest +import pretend -from twine import utils +from twine import utils, exceptions import helpers @@ -389,3 +390,18 @@ def t(foo=False): t(1) assert t(foo=True) + + +@pytest.mark.parametrize('repo_url', [ + "https://pypi.python.org", + "https://testpypi.python.org" +]) +def test_check_status_code_for_deprecated_pypi_url(repo_url): + response = pretend.stub( + status_code=410, + url=repo_url + ) + + # value of Verbose doesn't matter for this check + with pytest.raises(exceptions.UploadToDeprecatedPyPIDetected): + utils.check_status_code(response, False) diff --git a/twine/commands/upload.py b/twine/commands/upload.py index 78ef8478..8057dca9 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -20,8 +20,6 @@ from twine import settings from twine import utils -import requests - def skip_upload(response, skip_existing, package): filename = package.basefilename @@ -50,41 +48,6 @@ def skip_upload(response, skip_existing, package): (response.status_code == 403 and msg_403 in response.text))) -def check_status_code(response, verbose): - """Generate a helpful message based on the response from the repository. - - Raise a custom exception for recognized errors. Otherwise, print the - response content (based on the verbose option) before re-raising the - HTTPError. - """ - if response.status_code == 410 and "pypi.python.org" in response.url: - raise exceptions.UploadToDeprecatedPyPIDetected( - f"It appears you're uploading to pypi.python.org (or " - f"testpypi.python.org). You've received a 410 error response. " - f"Uploading to those sites is deprecated. The new sites are " - f"pypi.org and test.pypi.org. Try using {utils.DEFAULT_REPOSITORY}" - f" (or {utils.TEST_REPOSITORY}) to upload your packages instead. " - f"These are the default URLs for Twine now. More at " - f"https://packaging.python.org/guides/migrating-to-pypi-org/.") - elif response.status_code == 405 and "pypi.org" in response.url: - raise exceptions.InvalidPyPIUploadURL( - f"It appears you're trying to upload to pypi.org but have an " - f"invalid URL. You probably want one of these two URLs: " - f"{utils.DEFAULT_REPOSITORY} or {utils.TEST_REPOSITORY}. Check " - f"your --repository-url value.") - - try: - response.raise_for_status() - except requests.HTTPError as err: - if response.text: - if verbose: - print('Content received from server:\n{}'.format( - response.text)) - else: - print('NOTE: Try --verbose to see response content.') - raise err - - def upload(upload_settings, dists): dists = _find_dists(dists) @@ -136,7 +99,7 @@ def upload(upload_settings, dists): print(skip_message) continue - check_status_code(resp, upload_settings.verbose) + utils.check_status_code(resp, upload_settings.verbose) uploaded_packages.append(package) diff --git a/twine/utils.py b/twine/utils.py index 986681b3..9df0aa14 100644 --- a/twine/utils.py +++ b/twine/utils.py @@ -22,6 +22,7 @@ import configparser from urllib.parse import urlparse, urlunparse +import requests try: import keyring # noqa @@ -128,6 +129,41 @@ def normalize_repository_url(url): return urlunparse(parsed) +def check_status_code(response, verbose): + """Generate a helpful message based on the response from the repository. + + Raise a custom exception for recognized errors. Otherwise, print the + response content (based on the verbose option) before re-raising the + HTTPError. + """ + if response.status_code == 410 and "pypi.python.org" in response.url: + raise exceptions.UploadToDeprecatedPyPIDetected( + f"It appears you're uploading to pypi.python.org (or " + f"testpypi.python.org). You've received a 410 error response. " + f"Uploading to those sites is deprecated. The new sites are " + f"pypi.org and test.pypi.org. Try using {DEFAULT_REPOSITORY} (or " + f"{TEST_REPOSITORY}) to upload your packages instead. These are " + f"the default URLs for Twine now. More at " + f"https://packaging.python.org/guides/migrating-to-pypi-org/.") + elif response.status_code == 405 and "pypi.org" in response.url: + raise exceptions.InvalidPyPIUploadURL( + f"It appears you're trying to upload to pypi.org but have an " + f"invalid URL. You probably want one of these two URLs: " + f"{DEFAULT_REPOSITORY} or {TEST_REPOSITORY}. Check your " + f"--repository-url value.") + + try: + response.raise_for_status() + except requests.HTTPError as err: + if response.text: + if verbose: + print('Content received from server:\n{}'.format( + response.text)) + else: + print('NOTE: Try --verbose to see response content.') + raise err + + def get_userpass_value(cli_value, config, key, prompt_strategy=None): """Gets the username / password from config.