Skip to content

Commit

Permalink
Reformat HTTP errors (#666)
Browse files Browse the repository at this point in the history
* Separate exception handling

* Reformat HTTP error

* Add integration test

* Add __main__ to coverage

* Add test of HTTPError fallback

* Use exc.response instead of re

* Use fuzzy assertion for error message

* Refactor error formatting

* Shuffle status code and reason

* Tweak test regex
  • Loading branch information
bhrutledge authored Jun 22, 2020
1 parent cb7e116 commit 33d9611
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 12 deletions.
8 changes: 0 additions & 8 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,5 @@ exclude_lines =
# Don't complain if non-runnable code isn't run
if __name__ == .__main__.:


# Paths to omit from consideration
omit =
# __main__.py exists only as a very basic wrapper around warehouse.cli
# and exists only to provide setuptools and python -m a place to point
# at.
*/twine/__main__.py

[html]
show_contexts = True
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def entered_password(monkeypatch):
monkeypatch.setattr(getpass, "getpass", lambda prompt: "entered pw")


@pytest.fixture
@pytest.fixture(scope="session")
def sampleproject_dist(tmp_path_factory):
checkout = tmp_path_factory.mktemp("sampleproject", numbered=False)
subprocess.run(
Expand Down
28 changes: 28 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import re
import sys

import colorama
import pytest

from twine import __main__ as dunder_main
from twine import cli


Expand Down Expand Up @@ -46,6 +49,31 @@ def test_pypi_upload(sampleproject_dist):
cli.dispatch(command)


def test_pypi_error(sampleproject_dist, monkeypatch):
command = [
"twine",
"upload",
"--repository-url",
"https://test.pypi.org/legacy/",
"--username",
"foo",
"--password",
"bar",
str(sampleproject_dist),
]
monkeypatch.setattr(sys, "argv", command)

message = (
re.escape(colorama.Fore.RED)
+ r"HTTPError: 403 Forbidden from https://test\.pypi\.org/legacy/\n"
+ r".+?authentication"
)

result = dunder_main.main()

assert re.match(message, result)


@pytest.mark.xfail(
sys.platform == "win32",
reason="pytest-services watcher_getter fixture does not support Windows",
Expand Down
17 changes: 14 additions & 3 deletions twine/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import http
import sys
from typing import Any

Expand All @@ -24,9 +25,19 @@

def main() -> Any:
try:
return cli.dispatch(sys.argv[1:])
except (exceptions.TwineException, requests.HTTPError) as exc:
return _format_error(f"{exc.__class__.__name__}: {exc.args[0]}")
result = cli.dispatch(sys.argv[1:])
except requests.HTTPError as exc:
status_code = exc.response.status_code
status_phrase = http.HTTPStatus(status_code).phrase
result = (
f"{exc.__class__.__name__}: {status_code} {status_phrase} "
f"from {exc.response.url}\n"
f"{exc.response.reason}"
)
except exceptions.TwineException as exc:
result = f"{exc.__class__.__name__}: {exc.args[0]}"

return _format_error(result) if isinstance(result, str) else result


def _format_error(message: str) -> str:
Expand Down

0 comments on commit 33d9611

Please sign in to comment.