This commit is contained in:
Jakub Roztocil 2012-12-05 05:03:18 +01:00
parent 8175366f27
commit 53caf6ae72
4 changed files with 39 additions and 39 deletions

View File

@ -7,7 +7,8 @@ __version__ = '0.4.0-alpha'
__licence__ = 'BSD' __licence__ = 'BSD'
class exit: class ExitStatus:
"""Exit status code constants."""
OK = 0 OK = 0
ERROR = 1 ERROR = 1
ERROR_TIMEOUT = 2 ERROR_TIMEOUT = 2

View File

@ -22,23 +22,23 @@ from pygments import __version__ as pygments_version
from .cli import parser from .cli import parser
from .client import get_response from .client import get_response
from .models import Environment from .models import Environment
from .output import output_stream, write, write_with_colors_win_p3k from .output import build_output_stream, write, write_with_colors_win_p3k
from . import exit from . import ExitStatus
def get_exist_status(code, follow=False): def get_exist_status_code(code, follow=False):
"""Translate HTTP status code to exit status.""" """Translate HTTP status code to exit status code."""
if 300 <= code <= 399 and not follow: if 300 <= code <= 399 and not follow:
# Redirect # Redirect
return exit.ERROR_HTTP_3XX return ExitStatus.ERROR_HTTP_3XX
elif 400 <= code <= 499: elif 400 <= code <= 499:
# Client Error # Client Error
return exit.ERROR_HTTP_4XX return ExitStatus.ERROR_HTTP_4XX
elif 500 <= code <= 599: elif 500 <= code <= 599:
# Server Error # Server Error
return exit.ERROR_HTTP_5XX return ExitStatus.ERROR_HTTP_5XX
else: else:
return exit.OK return ExitStatus.OK
def print_debug_info(env): def print_debug_info(env):
@ -54,7 +54,7 @@ def print_debug_info(env):
def main(args=sys.argv[1:], env=Environment()): def main(args=sys.argv[1:], env=Environment()):
"""Run the main program and write the output to ``env.stdout``. """Run the main program and write the output to ``env.stdout``.
Return exit status. Return exit status code.
""" """
if env.config.default_options: if env.config.default_options:
@ -66,12 +66,12 @@ def main(args=sys.argv[1:], env=Environment()):
debug = '--debug' in args debug = '--debug' in args
traceback = debug or '--traceback' in args traceback = debug or '--traceback' in args
status = exit.OK exit_status_code = ExitStatus.OK
if debug: if debug:
print_debug_info(env) print_debug_info(env)
if args == ['--debug']: if args == ['--debug']:
sys.exit(exit.OK) return exit_status_code
try: try:
args = parser.parse_args(args=args, env=env) args = parser.parse_args(args=args, env=env)
@ -79,15 +79,14 @@ def main(args=sys.argv[1:], env=Environment()):
response = get_response(args, config_dir=env.config.directory) response = get_response(args, config_dir=env.config.directory)
if args.check_status: if args.check_status:
status = get_exist_status(response.status_code, exit_status_code = get_exist_status_code(response.status_code,
args.follow) args.follow)
if status and not env.stdout_isatty: if exit_status_code != ExitStatus.OK and not env.stdout_isatty:
error('%s %s', response.raw.status, response.raw.reason) error('%s %s', response.raw.status, response.raw.reason)
stream = output_stream(args, env, response.request, response)
write_kwargs = { write_kwargs = {
'stream': stream, 'stream': build_output_stream(
args, env, response.request, response),
'outfile': env.stdout, 'outfile': env.stdout,
'flush': env.stdout_isatty or args.stream 'flush': env.stdout_isatty or args.stream
} }
@ -108,16 +107,18 @@ def main(args=sys.argv[1:], env=Environment()):
if traceback: if traceback:
raise raise
env.stderr.write('\n') env.stderr.write('\n')
status = exit.ERROR exit_status_code = ExitStatus.ERROR
except requests.Timeout: except requests.Timeout:
status = exit.ERROR_TIMEOUT exit_status_code = ExitStatus.ERROR_TIMEOUT
error('Request timed out (%ss).', args.timeout) error('Request timed out (%ss).', args.timeout)
except Exception as e: except Exception as e:
# TODO: distinguish between expected and unexpected errors. # TODO: Better distinction between expected and unexpected errors.
# network errors vs. bugs, etc. # Network errors vs. bugs, etc.
if traceback: if traceback:
raise raise
error('%s: %s', type(e).__name__, str(e)) error('%s: %s', type(e).__name__, str(e))
status = exit.ERROR exit_status_code = ExitStatus.ERROR
return status return exit_status_code

View File

@ -78,23 +78,21 @@ def write_with_colors_win_p3k(stream, outfile, flush):
outfile.flush() outfile.flush()
def output_stream(args, env, request, response): def build_output_stream(args, env, request, response):
"""Build and return a chain of iterators over the `request`-`response` """Build and return a chain of iterators over the `request`-`response`
exchange each of which yields `bytes` chunks. exchange each of which yields `bytes` chunks.
""" """
Stream = make_stream(env, args)
req_h = OUT_REQ_HEAD in args.output_options req_h = OUT_REQ_HEAD in args.output_options
req_b = OUT_REQ_BODY in args.output_options req_b = OUT_REQ_BODY in args.output_options
resp_h = OUT_RESP_HEAD in args.output_options resp_h = OUT_RESP_HEAD in args.output_options
resp_b = OUT_RESP_BODY in args.output_options resp_b = OUT_RESP_BODY in args.output_options
req = req_h or req_b req = req_h or req_b
resp = resp_h or resp_b resp = resp_h or resp_b
output = [] output = []
Stream = get_stream_type(env, args)
if req: if req:
output.append(Stream( output.append(Stream(
@ -120,7 +118,7 @@ def output_stream(args, env, request, response):
return chain(*output) return chain(*output)
def make_stream(env, args): def get_stream_type(env, args):
"""Pick the right stream type based on `env` and `args`. """Pick the right stream type based on `env` and `args`.
Wrap it in a partial with the type-specific args so that Wrap it in a partial with the type-specific args so that
we don't need to think what stream we are dealing with. we don't need to think what stream we are dealing with.
@ -147,7 +145,7 @@ def make_stream(env, args):
class BaseStream(object): class BaseStream(object):
"""Base HTTP message stream class.""" """Base HTTP message output stream class."""
def __init__(self, msg, with_headers=True, with_body=True): def __init__(self, msg, with_headers=True, with_body=True):
""" """

View File

@ -56,7 +56,7 @@ from requests.compat import is_windows, is_py26, bytes, str
TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) TESTS_ROOT = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.realpath(os.path.join(TESTS_ROOT, '..'))) sys.path.insert(0, os.path.realpath(os.path.join(TESTS_ROOT, '..')))
from httpie import exit from httpie import ExitStatus
from httpie import input from httpie import input
from httpie.models import Environment from httpie.models import Environment
from httpie.core import main from httpie.core import main
@ -188,7 +188,7 @@ def http(*args, **kwargs):
sys.stderr.write(env.stderr.read()) sys.stderr.write(env.stderr.read())
raise raise
except SystemExit: except SystemExit:
exit_status = exit.ERROR exit_status = ExitStatus.ERROR
env.stdout.seek(0) env.stdout.seek(0)
env.stderr.seek(0) env.stderr.seek(0)
@ -895,7 +895,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/200') httpbin('/status/200')
) )
self.assertIn(OK, r) self.assertIn(OK, r)
self.assertEqual(r.exit_status, exit.OK) self.assertEqual(r.exit_status, ExitStatus.OK)
def test_error_response_exits_0_without_check_status(self): def test_error_response_exits_0_without_check_status(self):
r = http( r = http(
@ -903,7 +903,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/500') httpbin('/status/500')
) )
self.assertIn('HTTP/1.1 500', r) self.assertIn('HTTP/1.1 500', r)
self.assertEqual(r.exit_status, exit.OK) self.assertEqual(r.exit_status, ExitStatus.OK)
self.assertTrue(not r.stderr) self.assertTrue(not r.stderr)
def test_timeout_exit_status(self): def test_timeout_exit_status(self):
@ -912,7 +912,7 @@ class ExitStatusTest(BaseTestCase):
'GET', 'GET',
httpbin('/delay/1') httpbin('/delay/1')
) )
self.assertEqual(r.exit_status, exit.ERROR_TIMEOUT) self.assertEqual(r.exit_status, ExitStatus.ERROR_TIMEOUT)
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(self): def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(self):
r = http( r = http(
@ -923,7 +923,7 @@ class ExitStatusTest(BaseTestCase):
env=TestEnvironment(stdout_isatty=False,) env=TestEnvironment(stdout_isatty=False,)
) )
self.assertIn('HTTP/1.1 301', r) self.assertIn('HTTP/1.1 301', r)
self.assertEqual(r.exit_status, exit.ERROR_HTTP_3XX) self.assertEqual(r.exit_status, ExitStatus.ERROR_HTTP_3XX)
self.assertIn('301 moved permanently', r.stderr.lower()) self.assertIn('301 moved permanently', r.stderr.lower())
@skipIf(requests_version == '0.13.6', @skipIf(requests_version == '0.13.6',
@ -937,7 +937,7 @@ class ExitStatusTest(BaseTestCase):
) )
# The redirect will be followed so 200 is expected. # The redirect will be followed so 200 is expected.
self.assertIn('HTTP/1.1 200 OK', r) self.assertIn('HTTP/1.1 200 OK', r)
self.assertEqual(r.exit_status, exit.OK) self.assertEqual(r.exit_status, ExitStatus.OK)
def test_4xx_check_status_exits_4(self): def test_4xx_check_status_exits_4(self):
r = http( r = http(
@ -946,7 +946,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/401') httpbin('/status/401')
) )
self.assertIn('HTTP/1.1 401', r) self.assertIn('HTTP/1.1 401', r)
self.assertEqual(r.exit_status, exit.ERROR_HTTP_4XX) self.assertEqual(r.exit_status, ExitStatus.ERROR_HTTP_4XX)
# Also stderr should be empty since stdout isn't redirected. # Also stderr should be empty since stdout isn't redirected.
self.assertTrue(not r.stderr) self.assertTrue(not r.stderr)
@ -957,7 +957,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/500') httpbin('/status/500')
) )
self.assertIn('HTTP/1.1 500', r) self.assertIn('HTTP/1.1 500', r)
self.assertEqual(r.exit_status, exit.ERROR_HTTP_5XX) self.assertEqual(r.exit_status, ExitStatus.ERROR_HTTP_5XX)
class WindowsOnlyTests(BaseTestCase): class WindowsOnlyTests(BaseTestCase):