diff --git a/httpie/core.py b/httpie/core.py index 95f53abd..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 @@ -183,7 +186,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: diff --git a/requirements-dev.txt b/requirements-dev.txt index 359dad65..0578ada3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,5 @@ tox +mock pytest pytest-cov pytest-httpbin>=0.0.6 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).'