diff --git a/README.md b/README.md index 6c044376..d9d92ed2 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,11 @@ The data to be sent can also be passed via `stdin`: Most of the flags mirror the arguments you would use with `requests.request`. See `http -h`: - $ http -h - usage: http [-h] [--json | --form] [--traceback] [--ugly] [--headers | --body] - [--auth AUTH] [--verify VERIFY] [--proxy PROXY] - [--allow-redirects] [--file PATH] [--timeout TIMEOUT] - method URL [item [item ...]] + usage: httpie.py [-h] [--json | --form] [--traceback] [--ugly] + [--headers | --body] [--style STYLE] [--auth AUTH] + [--verify VERIFY] [--proxy PROXY] [--allow-redirects] + [--file PATH] [--timeout TIMEOUT] + method URL [item [item ...]] HTTPie - cURL for humans. @@ -62,6 +62,11 @@ Most of the flags mirror the arguments you would use with `requests.request`. Se --ugly, -u Do not prettify the response. --headers, -t Print only the response headers. --body, -b Print only the response body. + --style STYLE, -s STYLE + Output coloring style, one of autumn, borland, bw, + colorful, default, emacs, friendly, fruity, manni, + monokai, murphy, native, pastie, perldoc, solarized, + tango, trac, vim, vs. Defaults to solarized. --auth AUTH, -a AUTH username:password --verify VERIFY Set to "yes" to check the host's SSL certificate. You can also pass the path to a CA_BUNDLE file for private @@ -74,4 +79,3 @@ Most of the flags mirror the arguments you would use with `requests.request`. Se --file PATH File to multipart upload --timeout TIMEOUT Float describes the timeout of the request (Use socket.setdefaulttimeout() as fallback). - diff --git a/httpie/httpie.py b/httpie/httpie.py index ff6c136e..236044c2 100755 --- a/httpie/httpie.py +++ b/httpie/httpie.py @@ -66,8 +66,10 @@ group_only.add_argument('--headers', '-t', dest='print_body', group_only.add_argument('--body', '-b', dest='print_headers', action='store_false', default=True, help='Print only the response body.') -parser.add_argument('--style', '-s', dest='style', default='solarized', - help='Output coloring style') +parser.add_argument('--style', '-s', dest='style', default='solarized', metavar='STYLE', + choices=pretty.AVAILABLE_STYLES, + help='Output coloring style, one of %s. Defaults to solarized.' + % ', '.join(sorted(pretty.AVAILABLE_STYLES))) # ``requests.request`` keyword arguments. @@ -104,8 +106,13 @@ parser.add_argument('items', metavar='item', nargs='*', help='HTTP header (key:value) or data field (key=value)') -def main(): - args = parser.parse_args() +def main(args=None, + stdin=sys.stdin, + stdin_isatty=sys.stdout.isatty(), + stdout=sys.stdout, + stdout_isatty=sys.stdout.isatty()): + + args = parser.parse_args(args if args is not None else sys.argv[1:]) # Parse request headers and data from the command line. headers = CaseInsensitiveDict() @@ -115,18 +122,18 @@ def main(): if item.sep == SEP_COMMON: target = headers else: - if not sys.stdin.isatty(): + if not stdin_isatty: parser.error('Request body (stdin) and request ' 'data (key=value) cannot be mixed.') target = data target[item.key] = item.value - if not sys.stdin.isatty(): - data = sys.stdin.read() + if not stdin_isatty: + data = stdin.read() # JSON/Form content type. if args.json or (not args.form and data): - if sys.stdin.isatty(): + if stdin_isatty: data = json.dumps(data) if 'Content-Type' not in headers and (data or args.json): headers['Content-Type'] = TYPE_JSON @@ -167,19 +174,21 @@ def main(): response.content.decode(encoding) if response.content else u'' ) - if args.prettify and sys.stdout.isatty(): + if args.prettify and stdout_isatty: + prettify = pretty.PrettyHttp(args.style) if args.print_headers: - status_line = pretty.prettify_http(status_line, args.style).strip() - headers = pretty.prettify_http(headers, args.style) - if args.print_body: - body = pretty.prettify_body(body, - response.headers['content-type'], args.style) + status_line = prettify.headers(status_line).strip() + headers = prettify.headers(headers) + if args.print_body and 'content-type' in response.headers: + body = prettify.body(body, response.headers['content-type']) if args.print_headers: - print status_line - print headers + stdout.write(status_line) + stdout.write('\n') + stdout.write(headers) + stdout.write('\n') if args.print_body: - print body + stdout.write(body) if __name__ == '__main__': main() diff --git a/tests.py b/tests.py index 7ab258c9..6e5aec6c 100644 --- a/tests.py +++ b/tests.py @@ -1,3 +1,36 @@ import unittest +from StringIO import StringIO +from httpie import httpie +def http(*args, **kwargs): + stdout = StringIO() + httpie.main(args=args, stdout=stdout, + stdin_isatty=True, + stdout_isatty=False) + return stdout.getvalue() + + +# TODO: moar! + +class TestHTTPie(unittest.TestCase): + + def test_get(self): + http('GET', 'http://httpbin.org/get') + + def test_json(self): + response = http('POST', 'http://httpbin.org/post', 'foo=bar') + self.assertIn('"foo": "bar"', response) + + def test_form(self): + response = http('POST', '--form', 'http://httpbin.org/post', 'foo=bar') + self.assertIn('"foo": "bar"', response) + + def test_headers(self): + response = http('GET', 'http://httpbin.org/headers', 'Foo:bar') + self.assertIn('"User-Agent": "HTTPie', response) + self.assertIn('"Foo": "bar"', response) + + +if __name__ == '__main__': + unittest.main()