From 67d6426360930b77158cb1fd544e1f1bd4af83c3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 25 Apr 2012 00:08:40 +0200 Subject: [PATCH] Fixed several unicode-related issues Closes #31 Python 3 & non-ascii arguments => UnicodeEncodeError Closes #41 Unicode response error. Closes #42 UnicodeEncodeError when piping Unicode output --- httpie/__main__.py | 37 +++++++++++++++++++++---------------- httpie/cli.py | 44 +++++++++++++++++++++++--------------------- tests/tests.py | 12 ++++++++---- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/httpie/__main__.py b/httpie/__main__.py index 1759d1a0..3d27b299 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -6,7 +6,7 @@ try: except ImportError: OrderedDict = dict import requests -from requests.compat import urlparse, str +from requests.compat import urlparse, str, is_py3 from requests.structures import CaseInsensitiveDict from . import cli from . import pretty @@ -165,30 +165,35 @@ def main(args=None, prettifier = pretty.PrettyHttp(args.style) if do_prettify else None - output_request = (cli.OUT_REQUEST_HEADERS in args.output_options - or cli.OUT_REQUEST_BODY in args.output_options) + do_output_request = (cli.OUT_REQ_HEADERS in args.output_options + or cli.OUT_REQ_BODY in args.output_options) - output_response = (cli.OUT_RESPONSE_HEADERS in args.output_options - or cli.OUT_RESPONSE_BODY in args.output_options) + do_output_response = (cli.OUT_RESP_HEADERS in args.output_options + or cli.OUT_RESP_BODY in args.output_options) - if output_request: - stdout.write(format_http_message( + output = [] + if do_output_request: + output.append(format_http_message( message=make_request_message(response.request), prettifier=prettifier, - with_headers=cli.OUT_REQUEST_HEADERS in args.output_options, - with_body=cli.OUT_REQUEST_BODY in args.output_options + with_headers=cli.OUT_REQ_HEADERS in args.output_options, + with_body=cli.OUT_REQ_BODY in args.output_options )) - if output_response: - stdout.write(NEW_LINE) + if do_output_response: + output.append(NEW_LINE) - if output_response: - stdout.write(format_http_message( + if do_output_response: + output.append(format_http_message( message=make_response_message(response), prettifier=prettifier, - with_headers=cli.OUT_RESPONSE_HEADERS in args.output_options, - with_body=cli.OUT_RESPONSE_BODY in args.output_options + with_headers=cli.OUT_RESP_HEADERS in args.output_options, + with_body=cli.OUT_RESP_BODY in args.output_options )) - stdout.write(NEW_LINE) + output.append(NEW_LINE) + + output_bytes = ''.join(output).encode('utf8') + f = (stdout.buffer if is_py3 and hasattr(stdout, 'buffer') else stdout) + f.write(output_bytes) if __name__ == '__main__': diff --git a/httpie/cli.py b/httpie/cli.py index 29a55f6d..98338dc6 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -13,18 +13,20 @@ SEP_HEADERS = SEP_COMMON SEP_DATA = '=' SEP_DATA_RAW_JSON = ':=' SEP_FILES = '@' + + +OUT_REQ_HEADERS = 'H' +OUT_REQ_BODY = 'B' +OUT_RESP_HEADERS = 'h' +OUT_RESP_BODY = 'b' +OUTPUT_OPTIONS = [OUT_REQ_HEADERS, + OUT_REQ_BODY, + OUT_RESP_HEADERS, + OUT_RESP_BODY] + + PRETTIFY_STDOUT_TTY_ONLY = object() -OUT_REQUEST_HEADERS = 'H' -OUT_REQUEST_BODY = 'B' -OUT_RESPONSE_HEADERS = 'h' -OUT_RESPONSE_BODY = 'b' - -OUTPUT_OPTIONS = [OUT_REQUEST_HEADERS, - OUT_REQUEST_BODY, - OUT_RESPONSE_HEADERS, - OUT_RESPONSE_BODY] - class ParseError(Exception): pass @@ -34,6 +36,7 @@ KeyValue = namedtuple('KeyValue', ['key', 'value', 'sep', 'orig']) class KeyValueType(object): """A type used with `argparse`.""" + def __init__(self, *separators): self.separators = separators self.escapes = ['\\\\' + sep for sep in separators] @@ -56,7 +59,6 @@ class KeyValueType(object): found[start] = sep if not found: - #noinspection PyExceptionInherit raise argparse.ArgumentTypeError( '"%s" is not a valid value' % string) @@ -160,7 +162,7 @@ group_type.add_argument( ) -# output_options options. +# Output options. ############################################# parser.add_argument( @@ -189,7 +191,7 @@ prettify.add_argument( output_options = parser.add_mutually_exclusive_group(required=False) output_options.add_argument('--print', '-p', dest='output_options', - default=OUT_RESPONSE_HEADERS + OUT_RESPONSE_BODY, + default=OUT_RESP_HEADERS + OUT_RESP_BODY, help=_(''' String specifying what should the output contain. "{request_headers}" stands for request headers and @@ -199,10 +201,10 @@ output_options.add_argument('--print', '-p', dest='output_options', Defaults to "hb" which means that the whole response (headers and body) is printed. '''.format( - request_headers=OUT_REQUEST_HEADERS, - request_body=OUT_REQUEST_BODY, - response_headers=OUT_RESPONSE_HEADERS, - response_body=OUT_RESPONSE_BODY, + request_headers=OUT_REQ_HEADERS, + request_body=OUT_REQ_BODY, + response_headers=OUT_RESP_HEADERS, + response_body=OUT_RESP_BODY, )) ) output_options.add_argument( @@ -215,19 +217,19 @@ output_options.add_argument( ) output_options.add_argument( '--headers', '-t', dest='output_options', - action='store_const', const=OUT_RESPONSE_HEADERS, + action='store_const', const=OUT_RESP_HEADERS, help=_(''' Print only the response headers. Shortcut for --print={0}. - '''.format(OUT_RESPONSE_HEADERS)) + '''.format(OUT_RESP_HEADERS)) ) output_options.add_argument( '--body', '-b', dest='output_options', - action='store_const', const=OUT_RESPONSE_BODY, + action='store_const', const=OUT_RESP_BODY, help=_(''' Print only the response body. Shortcut for --print={0}. - '''.format(OUT_RESPONSE_BODY)) + '''.format(OUT_RESP_BODY)) ) parser.add_argument( diff --git a/tests/tests.py b/tests/tests.py index ea77d6ae..be39fb03 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -3,7 +3,8 @@ import os import sys import unittest import argparse -from requests.compat import StringIO, is_py26, str +from requests.compat import is_py26 +import tempfile TESTS_ROOT = os.path.dirname(__file__) @@ -22,9 +23,12 @@ def http(*args, **kwargs): 'stdout_isatty': False } http_kwargs.update(kwargs) - stdout = http_kwargs.setdefault('stdout', StringIO()) + stdout = http_kwargs.setdefault('stdout', tempfile.TemporaryFile()) __main__.main(args=args, **http_kwargs) - return stdout.getvalue() + stdout.seek(0) + response = stdout.read().decode('utf8') + stdout.close() + return response class BaseTest(unittest.TestCase): @@ -83,7 +87,7 @@ class TestItemParsing(BaseTest): self.assertDictEqual(data, { 'bob:=': 'foo', }) - + def test_valid_items(self): headers, data, files = cli.parse_items([ self.kv('string=value'),