mirror of
https://github.com/httpie/cli.git
synced 2026-06-20 11:32:56 +02:00
Added exit status constants, cleaned up main().
This commit is contained in:
1 parent
94c77c9bfc
commit
4e58a3849a
5 files changed
+149
-115
No files matched your search
@@ -5,3 +5,12 @@ HTTPie - cURL for humans.
|
||||
__author__ = 'Jakub Roztocil'
|
||||
__version__ = '0.2.7dev'
|
||||
__licence__ = 'BSD'
|
||||
|
||||
|
||||
class EXIT:
|
||||
OK = 0
|
||||
ERROR = 1
|
||||
# Used only when requested:
|
||||
ERROR_HTTP_3XX = 3
|
||||
ERROR_HTTP_4XX = 4
|
||||
ERROR_HTTP_5XX = 5
|
||||
+30
-94
@@ -13,27 +13,22 @@ Invocation flow:
|
||||
import sys
|
||||
import json
|
||||
import errno
|
||||
from itertools import chain
|
||||
from functools import partial
|
||||
|
||||
import requests
|
||||
import requests.auth
|
||||
from requests.compat import str
|
||||
|
||||
from .models import HTTPRequest, HTTPResponse, Environment
|
||||
from .output import (OutputProcessor, RawStream, PrettyStream,
|
||||
BufferedPrettyStream, EncodedStream)
|
||||
|
||||
from .input import (OUT_REQ_BODY, OUT_REQ_HEAD,
|
||||
OUT_RESP_HEAD, OUT_RESP_BODY)
|
||||
from .cli import parser
|
||||
from .models import Environment
|
||||
from .output import output_stream, write
|
||||
from . import EXIT
|
||||
|
||||
|
||||
FORM = 'application/x-www-form-urlencoded; charset=utf-8'
|
||||
JSON = 'application/json; charset=utf-8'
|
||||
|
||||
|
||||
def get_response(args, env):
|
||||
def get_response(args):
|
||||
"""Send the request and return a `request.Response`."""
|
||||
|
||||
auto_json = args.data and not args.form
|
||||
@@ -78,71 +73,19 @@ def get_response(args, env):
|
||||
)
|
||||
|
||||
|
||||
def output_stream(args, env, request, response):
|
||||
"""Format parts of the `request`-`response` exchange
|
||||
according to `args` and `env` and return `bytes`.
|
||||
|
||||
"""
|
||||
|
||||
# Pick the right stream type for this exchange based on `env` and `args`.
|
||||
if not env.stdout_isatty and not args.prettify:
|
||||
Stream = partial(
|
||||
RawStream,
|
||||
chunk_size=RawStream.CHUNK_SIZE_BY_LINE
|
||||
if args.stream
|
||||
else RawStream.CHUNK_SIZE)
|
||||
elif args.prettify:
|
||||
Stream = partial(
|
||||
PrettyStream if args.stream else BufferedPrettyStream,
|
||||
processor=OutputProcessor(env, pygments_style=args.style),
|
||||
env=env)
|
||||
else:
|
||||
Stream = partial(EncodedStream, env=env)
|
||||
|
||||
req_h = OUT_REQ_HEAD in args.output_options
|
||||
req_b = OUT_REQ_BODY in args.output_options
|
||||
resp_h = OUT_RESP_HEAD in args.output_options
|
||||
resp_b = OUT_RESP_BODY in args.output_options
|
||||
|
||||
req = req_h or req_b
|
||||
resp = resp_h or resp_b
|
||||
|
||||
output = []
|
||||
|
||||
if req:
|
||||
output.append(Stream(
|
||||
msg=HTTPRequest(request),
|
||||
with_headers=req_h,
|
||||
with_body=req_b))
|
||||
|
||||
if req and resp:
|
||||
output.append([b'\n\n\n'])
|
||||
|
||||
if resp:
|
||||
output.append(Stream(
|
||||
msg=HTTPResponse(response),
|
||||
with_headers=resp_h,
|
||||
with_body=resp_b))
|
||||
|
||||
if env.stdout_isatty:
|
||||
output.append([b'\n\n'])
|
||||
|
||||
return chain(*output)
|
||||
|
||||
|
||||
def get_exist_status(code, allow_redirects=False):
|
||||
"""Translate HTTP status code to exit status."""
|
||||
if 300 <= code <= 399 and not allow_redirects:
|
||||
# Redirect
|
||||
return 3
|
||||
return EXIT.ERROR_HTTP_3XX
|
||||
elif 400 <= code <= 499:
|
||||
# Client Error
|
||||
return 4
|
||||
return EXIT.ERROR_HTTP_4XX
|
||||
elif 500 <= code <= 599:
|
||||
# Server Error
|
||||
return 5
|
||||
return EXIT.ERROR_HTTP_5XX
|
||||
else:
|
||||
return 0
|
||||
return EXIT.OK
|
||||
|
||||
|
||||
def main(args=sys.argv[1:], env=Environment()):
|
||||
@@ -151,57 +94,50 @@ def main(args=sys.argv[1:], env=Environment()):
|
||||
Return exit status.
|
||||
|
||||
"""
|
||||
debug = '--debug' in args
|
||||
|
||||
if env.is_windows and not env.stdout_isatty:
|
||||
env.stderr.write(
|
||||
'http: error: Output redirection is not supported on Windows.'
|
||||
' Please use `--output FILE\' instead.\n')
|
||||
return 1
|
||||
def error(msg, *args):
|
||||
msg = msg % args
|
||||
env.stderr.write('http: error: %s\n' % msg)
|
||||
|
||||
debug = '--debug' in args
|
||||
status = EXIT.OK
|
||||
|
||||
try:
|
||||
args = parser.parse_args(args=args, env=env)
|
||||
response = get_response(args, env)
|
||||
status = 0
|
||||
response = get_response(args)
|
||||
|
||||
if args.check_status:
|
||||
status = get_exist_status(response.status_code,
|
||||
args.allow_redirects)
|
||||
if status and not env.stdout_isatty:
|
||||
err = 'http error: %s %s\n' % (
|
||||
response.raw.status, response.raw.reason)
|
||||
env.stderr.write(err)
|
||||
error('%s %s', response.raw.status, response.raw.reason)
|
||||
|
||||
stream = output_stream(args, env, response.request, response)
|
||||
|
||||
try:
|
||||
# We are writing bytes so we use buffer on Python 3
|
||||
buffer = env.stdout.buffer
|
||||
except AttributeError:
|
||||
buffer = env.stdout
|
||||
|
||||
try:
|
||||
for chunk in output_stream(args, env, response.request, response):
|
||||
buffer.write(chunk)
|
||||
if env.stdout_isatty or args.stream:
|
||||
env.stdout.flush()
|
||||
write(stream=stream,
|
||||
outfile=env.stdout,
|
||||
flush=env.stdout_isatty or args.stream)
|
||||
|
||||
except IOError as e:
|
||||
if debug:
|
||||
raise
|
||||
if e.errno == errno.EPIPE:
|
||||
if not debug and e.errno == errno.EPIPE:
|
||||
# Ignore broken pipes unless --debug.
|
||||
env.stderr.write('\n')
|
||||
else:
|
||||
env.stderr.write(str(e) + '\n')
|
||||
return 1
|
||||
raise
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
if debug:
|
||||
raise
|
||||
env.stderr.write('\n')
|
||||
return 1
|
||||
status = EXIT.ERROR
|
||||
|
||||
except Exception as e:
|
||||
# TODO: distinguish between expected and unexpected errors.
|
||||
# network errors vs. bugs, etc.
|
||||
if debug:
|
||||
raise
|
||||
env.stderr.write(str(e) + '\n')
|
||||
return 1
|
||||
error('%s: %s', type(e).__name__, str(e))
|
||||
status = EXIT.ERROR
|
||||
|
||||
return status
|
||||
+4
-3
@@ -95,6 +95,10 @@ class Parser(argparse.ArgumentParser):
|
||||
|
||||
self.env = env
|
||||
|
||||
if env.is_windows and not env.stdout_isatty:
|
||||
self.error('Output redirection is not supported on Windows.'
|
||||
' Please use `--output FILE\' instead.')
|
||||
|
||||
args = super(Parser, self).parse_args(args, namespace)
|
||||
|
||||
if args.output:
|
||||
@@ -131,9 +135,6 @@ class Parser(argparse.ArgumentParser):
|
||||
None: self.env.stderr
|
||||
}.get(file, file)
|
||||
|
||||
#if isinstance(message, str):
|
||||
# message = message.encode('utf8')
|
||||
|
||||
super(Parser, self)._print_message(message, file)
|
||||
|
||||
def _body_from_file(self, args, fd):
|
||||
|
||||
+81
-1
@@ -2,6 +2,8 @@
|
||||
|
||||
"""
|
||||
import json
|
||||
from functools import partial
|
||||
from itertools import chain
|
||||
|
||||
import pygments
|
||||
from pygments import token, lexer
|
||||
@@ -13,7 +15,9 @@ from pygments.util import ClassNotFound
|
||||
from requests.compat import is_windows
|
||||
|
||||
from .solarized import Solarized256Style
|
||||
from .models import Environment
|
||||
from .models import HTTPRequest, HTTPResponse, Environment
|
||||
from .input import (OUT_REQ_BODY, OUT_REQ_HEAD,
|
||||
OUT_RESP_HEAD, OUT_RESP_BODY)
|
||||
|
||||
|
||||
# Colors on Windows via colorama aren't that great and fruity
|
||||
@@ -43,6 +47,82 @@ class BinarySuppressedError(Exception):
|
||||
# Output Streams
|
||||
###############################################################################
|
||||
|
||||
|
||||
def write(stream, outfile, flush):
|
||||
"""Write the output stream."""
|
||||
try:
|
||||
# Writing bytes so we use the buffer interface (Python 3).
|
||||
buf = outfile.buffer
|
||||
except AttributeError:
|
||||
buf = outfile
|
||||
|
||||
for chunk in stream:
|
||||
buf.write(chunk)
|
||||
if flush:
|
||||
outfile.flush()
|
||||
|
||||
|
||||
def output_stream(args, env, request, response):
|
||||
"""Build and return a chain of iterators over the `request`-`response`
|
||||
exchange each of which yields `bytes` chunks.
|
||||
|
||||
"""
|
||||
|
||||
Stream = make_stream(env, args)
|
||||
|
||||
req_h = OUT_REQ_HEAD in args.output_options
|
||||
req_b = OUT_REQ_BODY in args.output_options
|
||||
resp_h = OUT_RESP_HEAD in args.output_options
|
||||
resp_b = OUT_RESP_BODY in args.output_options
|
||||
|
||||
req = req_h or req_b
|
||||
resp = resp_h or resp_b
|
||||
|
||||
output = []
|
||||
|
||||
if req:
|
||||
output.append(Stream(
|
||||
msg=HTTPRequest(request),
|
||||
with_headers=req_h,
|
||||
with_body=req_b))
|
||||
|
||||
if req and resp:
|
||||
output.append([b'\n\n\n'])
|
||||
|
||||
if resp:
|
||||
output.append(Stream(
|
||||
msg=HTTPResponse(response),
|
||||
with_headers=resp_h,
|
||||
with_body=resp_b))
|
||||
|
||||
if env.stdout_isatty:
|
||||
output.append([b'\n\n'])
|
||||
|
||||
return chain(*output)
|
||||
|
||||
|
||||
def make_stream(env, args):
|
||||
"""Pick the right stream type for based on `env` and `args`.
|
||||
and wrap it with a partial with the type-specific args.
|
||||
|
||||
"""
|
||||
if not env.stdout_isatty and not args.prettify:
|
||||
Stream = partial(
|
||||
RawStream,
|
||||
chunk_size=RawStream.CHUNK_SIZE_BY_LINE
|
||||
if args.stream
|
||||
else RawStream.CHUNK_SIZE)
|
||||
elif args.prettify:
|
||||
Stream = partial(
|
||||
PrettyStream if args.stream else BufferedPrettyStream,
|
||||
processor=OutputProcessor(env, pygments_style=args.style),
|
||||
env=env)
|
||||
else:
|
||||
Stream = partial(EncodedStream, env=env)
|
||||
|
||||
return Stream
|
||||
|
||||
|
||||
class BaseStream(object):
|
||||
"""Base HTTP message stream class."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user