2012-07-26 07:37:03 +03:00
|
|
|
"""This module provides the main functionality of HTTPie.
|
|
|
|
|
|
|
|
Invocation flow:
|
|
|
|
|
|
|
|
1. Read, validate and process the input (args, `stdin`).
|
2012-08-03 02:01:15 +03:00
|
|
|
2. Create and send a request.
|
|
|
|
3. Stream, and possibly process and format, the requested parts
|
|
|
|
of the request-response exchange.
|
|
|
|
4. Simultaneously write to `stdout`
|
|
|
|
5. Exit.
|
2012-07-26 07:37:03 +03:00
|
|
|
|
|
|
|
"""
|
2012-07-21 03:59:43 +03:00
|
|
|
import sys
|
2012-08-03 02:01:15 +03:00
|
|
|
import errno
|
2012-07-26 01:26:23 +03:00
|
|
|
|
2012-07-21 03:59:43 +03:00
|
|
|
import requests
|
2012-08-17 07:35:18 +03:00
|
|
|
from requests.compat import str, is_py3
|
2012-08-07 15:50:51 +03:00
|
|
|
from httpie import __version__ as httpie_version
|
|
|
|
from requests import __version__ as requests_version
|
|
|
|
from pygments import __version__ as pygments_version
|
2012-07-26 01:26:23 +03:00
|
|
|
|
2012-07-26 07:37:03 +03:00
|
|
|
from .cli import parser
|
2012-08-18 00:23:02 +03:00
|
|
|
from .client import get_response
|
2012-08-04 20:12:51 +03:00
|
|
|
from .models import Environment
|
2012-08-17 07:35:18 +03:00
|
|
|
from .output import output_stream, write, write_with_colors_win_p3k
|
2012-09-17 01:37:36 +03:00
|
|
|
from .config import DEFAULT_CONFIG_DIR, Config
|
2012-08-04 20:12:51 +03:00
|
|
|
from . import EXIT
|
2012-07-21 03:59:43 +03:00
|
|
|
|
|
|
|
|
2012-09-07 12:58:39 +03:00
|
|
|
def get_exist_status(code, follow=False):
|
2012-07-26 07:37:03 +03:00
|
|
|
"""Translate HTTP status code to exit status."""
|
2012-09-07 12:58:39 +03:00
|
|
|
if 300 <= code <= 399 and not follow:
|
2012-07-23 20:35:44 +03:00
|
|
|
# Redirect
|
2012-08-04 20:12:51 +03:00
|
|
|
return EXIT.ERROR_HTTP_3XX
|
2012-07-23 20:35:44 +03:00
|
|
|
elif 400 <= code <= 499:
|
|
|
|
# Client Error
|
2012-08-04 20:12:51 +03:00
|
|
|
return EXIT.ERROR_HTTP_4XX
|
2012-07-23 20:35:44 +03:00
|
|
|
elif 500 <= code <= 599:
|
|
|
|
# Server Error
|
2012-08-04 20:12:51 +03:00
|
|
|
return EXIT.ERROR_HTTP_5XX
|
2012-07-23 20:35:44 +03:00
|
|
|
else:
|
2012-08-04 20:12:51 +03:00
|
|
|
return EXIT.OK
|
2012-07-23 20:35:44 +03:00
|
|
|
|
|
|
|
|
2012-09-17 01:37:36 +03:00
|
|
|
def print_debug_info(env):
|
2012-08-18 05:37:22 +03:00
|
|
|
sys.stderr.writelines([
|
|
|
|
'HTTPie %s\n' % httpie_version,
|
2012-09-17 01:37:36 +03:00
|
|
|
'HTTPie data: %s\n' % env.config.directory,
|
2012-08-18 05:37:22 +03:00
|
|
|
'Requests %s\n' % requests_version,
|
|
|
|
'Pygments %s\n' % pygments_version,
|
|
|
|
'Python %s %s\n' % (sys.version, sys.platform)
|
|
|
|
])
|
|
|
|
|
|
|
|
|
2012-07-21 03:59:43 +03:00
|
|
|
def main(args=sys.argv[1:], env=Environment()):
|
2012-07-26 07:37:03 +03:00
|
|
|
"""Run the main program and write the output to ``env.stdout``.
|
2012-07-23 20:35:44 +03:00
|
|
|
|
|
|
|
Return exit status.
|
|
|
|
|
|
|
|
"""
|
2012-07-30 11:58:16 +03:00
|
|
|
|
2012-08-04 20:12:51 +03:00
|
|
|
def error(msg, *args):
|
|
|
|
msg = msg % args
|
2012-08-07 01:07:04 +03:00
|
|
|
env.stderr.write('\nhttp: error: %s\n' % msg)
|
2012-08-04 20:12:51 +03:00
|
|
|
|
|
|
|
debug = '--debug' in args
|
2012-08-07 15:50:51 +03:00
|
|
|
traceback = debug or '--traceback' in args
|
2012-08-04 20:12:51 +03:00
|
|
|
status = EXIT.OK
|
2012-07-30 11:58:16 +03:00
|
|
|
|
2012-08-07 15:50:51 +03:00
|
|
|
if debug:
|
2012-09-17 01:37:36 +03:00
|
|
|
print_debug_info(env)
|
2012-08-18 05:37:22 +03:00
|
|
|
if args == ['--debug']:
|
|
|
|
sys.exit(EXIT.OK)
|
2012-08-07 15:50:51 +03:00
|
|
|
|
2012-07-30 11:58:16 +03:00
|
|
|
try:
|
2012-08-02 00:21:52 +03:00
|
|
|
args = parser.parse_args(args=args, env=env)
|
2012-08-18 00:23:02 +03:00
|
|
|
response = get_response(args)
|
2012-08-02 00:21:52 +03:00
|
|
|
|
|
|
|
if args.check_status:
|
|
|
|
status = get_exist_status(response.status_code,
|
2012-09-07 12:58:39 +03:00
|
|
|
args.follow)
|
2012-08-02 00:21:52 +03:00
|
|
|
if status and not env.stdout_isatty:
|
2012-08-04 20:12:51 +03:00
|
|
|
error('%s %s', response.raw.status, response.raw.reason)
|
2012-08-02 00:21:52 +03:00
|
|
|
|
2012-08-04 20:12:51 +03:00
|
|
|
stream = output_stream(args, env, response.request, response)
|
2012-08-02 00:21:52 +03:00
|
|
|
|
2012-08-17 07:35:18 +03:00
|
|
|
write_kwargs = {
|
|
|
|
'stream': stream,
|
|
|
|
'outfile': env.stdout,
|
|
|
|
'flush': env.stdout_isatty or args.stream
|
|
|
|
}
|
2012-08-03 02:01:15 +03:00
|
|
|
try:
|
2012-08-17 07:35:18 +03:00
|
|
|
if env.is_windows and is_py3 and 'colors' in args.prettify:
|
|
|
|
write_with_colors_win_p3k(**write_kwargs)
|
|
|
|
else:
|
|
|
|
write(**write_kwargs)
|
2012-08-03 02:01:15 +03:00
|
|
|
|
|
|
|
except IOError as e:
|
2012-08-07 15:50:51 +03:00
|
|
|
if not traceback and e.errno == errno.EPIPE:
|
2012-08-07 19:22:47 +03:00
|
|
|
# Ignore broken pipes unless --traceback.
|
2012-08-03 02:01:15 +03:00
|
|
|
env.stderr.write('\n')
|
|
|
|
else:
|
2012-08-04 20:12:51 +03:00
|
|
|
raise
|
2012-08-02 00:21:52 +03:00
|
|
|
|
|
|
|
except (KeyboardInterrupt, SystemExit):
|
2012-08-07 15:50:51 +03:00
|
|
|
if traceback:
|
2012-08-03 02:01:15 +03:00
|
|
|
raise
|
2012-08-02 00:21:52 +03:00
|
|
|
env.stderr.write('\n')
|
2012-08-04 20:12:51 +03:00
|
|
|
status = EXIT.ERROR
|
2012-08-07 19:22:47 +03:00
|
|
|
except requests.Timeout:
|
|
|
|
status = EXIT.ERROR_TIMEOUT
|
|
|
|
error('Request timed out (%ss).', args.timeout)
|
2012-08-02 00:21:52 +03:00
|
|
|
except Exception as e:
|
2012-08-04 20:12:51 +03:00
|
|
|
# TODO: distinguish between expected and unexpected errors.
|
|
|
|
# network errors vs. bugs, etc.
|
2012-08-07 15:50:51 +03:00
|
|
|
if traceback:
|
2012-08-02 00:21:52 +03:00
|
|
|
raise
|
2012-08-04 20:12:51 +03:00
|
|
|
error('%s: %s', type(e).__name__, str(e))
|
|
|
|
status = EXIT.ERROR
|
2012-07-24 02:09:14 +03:00
|
|
|
|
|
|
|
return status
|