From 7f8adad313999775992396fc39f6ccb5bdfd5af4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Wed, 4 Feb 2015 10:34:43 -0800 Subject: [PATCH 1/2] Print info about request on error This can help in diagnosing certain issues. For example, if I were trying to use a "http+unix" URL but I don't have #299, then I'll get the following: [marca@marca-mac2 httpie]$ http http+unix://%2Ftmp%2Fprofilesvc.sock/status/pid http: error: ConnectionError: ('Connection aborted.', gaierror(8, 'nodename nor servname provided, or not known')) while doing GET request to URL: http://http+unix//%2Ftmp%2Fprofilesvc.sock/status/pid Having the URL in the error message is super useful here so that I know an extra `http://` is getting prepended and it's not doing what I expected. --- httpie/core.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/httpie/core.py b/httpie/core.py index 95f53abd..83910ec7 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -183,7 +183,13 @@ def main(args=sys.argv[1:], env=Environment()): # Network errors vs. bugs, etc. if traceback: raise - error('%s: %s', type(e).__name__, str(e)) + msg = str(e) + if hasattr(e, 'request'): + request = e.request + if hasattr(request, 'url'): + msg += ' while doing %s request to URL: %s' % ( + request.method, request.url) + error('%s: %s', type(e).__name__, msg) exit_status = ExitStatus.ERROR finally: From f855de16c2c763241abc04594a89f4dfc6db3485 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 8 Feb 2015 08:17:35 -0800 Subject: [PATCH 2/2] Increase test coverage for error handling --- httpie/core.py | 7 +++++-- requirements-dev.txt | 1 + tests/test_errors.py | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/test_errors.py diff --git a/httpie/core.py b/httpie/core.py index 83910ec7..1660b93b 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -67,7 +67,7 @@ def decode_args(args, stdin_encoding): ] -def main(args=sys.argv[1:], env=Environment()): +def main(args=sys.argv[1:], env=Environment(), error=None): """Run the main program and write the output to ``env.stdout``. Return exit status code. @@ -81,11 +81,14 @@ def main(args=sys.argv[1:], env=Environment()): if env.config.default_options: args = env.config.default_options + args - def error(msg, *args, **kwargs): + def _error(msg, *args, **kwargs): msg = msg % args level = kwargs.get('level', 'error') env.stderr.write('\nhttp: %s: %s\n' % (level, msg)) + if error is None: + error = _error + debug = '--debug' in args traceback = debug or '--traceback' in args exit_status = ExitStatus.OK diff --git a/requirements-dev.txt b/requirements-dev.txt index 16fcc9cb..9e132deb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,5 @@ tox +mock pytest pytest-cov pytest-httpbin diff --git a/tests/test_errors.py b/tests/test_errors.py new file mode 100644 index 00000000..1d7cf24c --- /dev/null +++ b/tests/test_errors.py @@ -0,0 +1,48 @@ +import mock +from pytest import raises +from requests import Request, Timeout +from requests.exceptions import ConnectionError + +from httpie.core import main + +error_msg = None + + +@mock.patch('httpie.core.get_response') +def test_error(get_response): + def error(msg, *args, **kwargs): + global error_msg + error_msg = msg % args + + exc = ConnectionError('Connection aborted') + exc.request = Request(method='GET', url='http://www.google.com') + get_response.side_effect = exc + ret = main(['--ignore-stdin', 'www.google.com'], error=error) + assert ret == 1 + assert error_msg == ( + 'ConnectionError: ' + 'Connection aborted while doing GET request to URL: ' + 'http://www.google.com') + + +@mock.patch('httpie.core.get_response') +def test_error_traceback(get_response): + exc = ConnectionError('Connection aborted') + exc.request = Request(method='GET', url='http://www.google.com') + get_response.side_effect = exc + with raises(ConnectionError): + ret = main(['--ignore-stdin', '--traceback', 'www.google.com']) + + +@mock.patch('httpie.core.get_response') +def test_timeout(get_response): + def error(msg, *args, **kwargs): + global error_msg + error_msg = msg % args + + exc = Timeout('Request timed out') + exc.request = Request(method='GET', url='http://www.google.com') + get_response.side_effect = exc + ret = main(['--ignore-stdin', 'www.google.com'], error=error) + assert ret == 2 + assert error_msg == 'Request timed out (30s).'