mirror of
https://github.com/httpie/cli.git
synced 2025-06-20 17:47:48 +02:00
Revorked output
Binary now works everywhere. Also added `--output FILE` for Windows.
This commit is contained in:
parent
6eed0d92eb
commit
923a8b71bd
@ -334,6 +334,8 @@ Changelog
|
|||||||
=========
|
=========
|
||||||
|
|
||||||
* `0.2.7dev`_
|
* `0.2.7dev`_
|
||||||
|
* Windows: Added ``--output FILE`` to store output into a file
|
||||||
|
(piping results into corrupted data on Windows).
|
||||||
* Proper handling of binary requests and responses.
|
* Proper handling of binary requests and responses.
|
||||||
* Fixed printing of ``multipart/form-data`` requests.
|
* Fixed printing of ``multipart/form-data`` requests.
|
||||||
* Renamed ``--traceback`` to ``--debug``.
|
* Renamed ``--traceback`` to ``--debug``.
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
NOTE: the CLI interface may change before reaching v1.0.
|
NOTE: the CLI interface may change before reaching v1.0.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from requests.compat import is_windows
|
||||||
|
|
||||||
from . import __doc__
|
from . import __doc__
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .output import AVAILABLE_STYLES
|
from .output import AVAILABLE_STYLES
|
||||||
@ -50,12 +54,19 @@ group_type.add_argument(
|
|||||||
# Output options.
|
# Output options.
|
||||||
#############################################
|
#############################################
|
||||||
|
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--debug', action='store_true', default=False,
|
'--output', '-o', type=argparse.FileType('wb'),
|
||||||
help=_('''
|
metavar='FILE',
|
||||||
Prints exception traceback should one occur and other
|
help= argparse.SUPPRESS if not is_windows else _(
|
||||||
information useful for debugging HTTPie itself.
|
'''
|
||||||
''')
|
Save output to FILE.
|
||||||
|
This option is a replacement for piping output to FILE,
|
||||||
|
which would on Windows result into corrupted data
|
||||||
|
being saved.
|
||||||
|
|
||||||
|
'''
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
prettify = parser.add_mutually_exclusive_group(required=False)
|
prettify = parser.add_mutually_exclusive_group(required=False)
|
||||||
@ -200,6 +211,13 @@ parser.add_argument(
|
|||||||
(Use socket.setdefaulttimeout() as fallback).
|
(Use socket.setdefaulttimeout() as fallback).
|
||||||
''')
|
''')
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--debug', action='store_true', default=False,
|
||||||
|
help=_('''
|
||||||
|
Prints exception traceback should one occur and other
|
||||||
|
information useful for debugging HTTPie itself.
|
||||||
|
''')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Positional arguments.
|
# Positional arguments.
|
||||||
|
@ -148,7 +148,15 @@ def main(args=sys.argv[1:], env=Environment()):
|
|||||||
Return exit status.
|
Return exit status.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
args = parser.parse_args(args=args, env=env)
|
args = parser.parse_args(args=args, env=env)
|
||||||
|
|
||||||
response = get_response(args, env)
|
response = get_response(args, env)
|
||||||
|
|
||||||
status = 0
|
status = 0
|
||||||
@ -159,12 +167,13 @@ def main(args=sys.argv[1:], env=Environment()):
|
|||||||
if status and not env.stdout_isatty:
|
if status and not env.stdout_isatty:
|
||||||
err = 'http error: %s %s\n' % (
|
err = 'http error: %s %s\n' % (
|
||||||
response.raw.status, response.raw.reason)
|
response.raw.status, response.raw.reason)
|
||||||
env.stderr.write(err.encode('utf8'))
|
env.stderr.write(err)
|
||||||
|
|
||||||
output_bytes = get_output(args, env, response.request, response)
|
output = get_output(args, env, response.request, response)
|
||||||
|
|
||||||
# output_bytes = output.encode('utf8')
|
try:
|
||||||
f = getattr(env.stdout, 'buffer', env.stdout)
|
env.stdout.buffer.write(output)
|
||||||
f.write(output_bytes)
|
except AttributeError:
|
||||||
|
env.stdout.write(output)
|
||||||
|
|
||||||
return status
|
return status
|
||||||
|
@ -89,8 +89,15 @@ class Parser(argparse.ArgumentParser):
|
|||||||
|
|
||||||
#noinspection PyMethodOverriding
|
#noinspection PyMethodOverriding
|
||||||
def parse_args(self, env, args=None, namespace=None):
|
def parse_args(self, env, args=None, namespace=None):
|
||||||
|
|
||||||
|
self.env = env
|
||||||
|
|
||||||
args = super(Parser, self).parse_args(args, namespace)
|
args = super(Parser, self).parse_args(args, namespace)
|
||||||
|
|
||||||
|
if args.output:
|
||||||
|
env.stdout = args.output
|
||||||
|
env.stdout_isatty = False
|
||||||
|
|
||||||
self._process_output_options(args, env)
|
self._process_output_options(args, env)
|
||||||
self._guess_method(args, env)
|
self._guess_method(args, env)
|
||||||
self._parse_items(args)
|
self._parse_items(args)
|
||||||
@ -104,9 +111,24 @@ class Parser(argparse.ArgumentParser):
|
|||||||
|
|
||||||
if args.prettify == PRETTIFY_STDOUT_TTY_ONLY:
|
if args.prettify == PRETTIFY_STDOUT_TTY_ONLY:
|
||||||
args.prettify = env.stdout_isatty
|
args.prettify = env.stdout_isatty
|
||||||
|
elif args.prettify and env.is_windows:
|
||||||
|
self.error('Only terminal output can be prettified on Windows.')
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
def _print_message(self, message, file=None):
|
||||||
|
# Sneak in our stderr/stdout.
|
||||||
|
file = {
|
||||||
|
sys.stdout: self.env.stdout,
|
||||||
|
sys.stderr: self.env.stderr,
|
||||||
|
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, data):
|
def _body_from_file(self, args, data):
|
||||||
"""There can only be one source of request data."""
|
"""There can only be one source of request data."""
|
||||||
if args.data:
|
if args.data:
|
||||||
@ -398,7 +420,7 @@ def parse_items(items, data=None, headers=None, files=None, params=None):
|
|||||||
target = params
|
target = params
|
||||||
elif item.sep == SEP_FILES:
|
elif item.sep == SEP_FILES:
|
||||||
try:
|
try:
|
||||||
with open(os.path.expanduser(value), 'r') as f:
|
with open(os.path.expanduser(value)) as f:
|
||||||
value = (os.path.basename(f.name), f.read())
|
value = (os.path.basename(f.name), f.read())
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
raise ParseError(
|
raise ParseError(
|
||||||
|
@ -10,23 +10,18 @@ class Environment(object):
|
|||||||
and allows for mocking.
|
and allows for mocking.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
#noinspection PyUnresolvedReferences
|
||||||
|
is_windows = is_windows
|
||||||
|
|
||||||
progname = os.path.basename(sys.argv[0])
|
progname = os.path.basename(sys.argv[0])
|
||||||
if progname not in ['http', 'https']:
|
if progname not in ['http', 'https']:
|
||||||
progname = 'http'
|
progname = 'http'
|
||||||
|
|
||||||
stdin_isatty = sys.stdin.isatty()
|
stdin_isatty = sys.stdin.isatty()
|
||||||
stdin = sys.stdin
|
stdin = sys.stdin
|
||||||
|
|
||||||
if is_windows:
|
|
||||||
# `colorama` patches `sys.stdout` so its initialization
|
|
||||||
# needs to happen before the default environment is set.
|
|
||||||
import colorama
|
|
||||||
colorama.init()
|
|
||||||
del colorama
|
|
||||||
|
|
||||||
stdout_isatty = sys.stdout.isatty()
|
stdout_isatty = sys.stdout.isatty()
|
||||||
stdout = sys.stdout
|
stdout = sys.stdout
|
||||||
|
|
||||||
stderr = sys.stderr
|
stderr = sys.stderr
|
||||||
|
|
||||||
# Can be set to 0 to disable colors completely.
|
# Can be set to 0 to disable colors completely.
|
||||||
@ -35,6 +30,18 @@ class Environment(object):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.__dict__.update(**kwargs)
|
self.__dict__.update(**kwargs)
|
||||||
|
|
||||||
|
def init_colors(self):
|
||||||
|
# We check for real Window here, not self.is_windows as
|
||||||
|
# it could be mocked.
|
||||||
|
if (is_windows and not self.__colors_initialized
|
||||||
|
and self.stdout == sys.stdout):
|
||||||
|
import colorama.initialise
|
||||||
|
self.stdout = colorama.initialise.wrap_stream(
|
||||||
|
self.stdout, autoreset=False,
|
||||||
|
convert=None, strip=None, wrap=True)
|
||||||
|
self.__colors_initialized = True
|
||||||
|
__colors_initialized = False
|
||||||
|
|
||||||
|
|
||||||
class HTTPMessage(object):
|
class HTTPMessage(object):
|
||||||
"""Model representing an HTTP message."""
|
"""Model representing an HTTP message."""
|
||||||
@ -49,7 +56,7 @@ class HTTPMessage(object):
|
|||||||
self.line = line # {Request,Status}-Line
|
self.line = line # {Request,Status}-Line
|
||||||
self.headers = headers
|
self.headers = headers
|
||||||
self.body = body
|
self.body = body
|
||||||
self.encoding = encoding
|
self.encoding = encoding or 'utf8'
|
||||||
self.content_type = content_type
|
self.content_type = content_type
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -41,7 +41,26 @@ def format(msg, prettifier=None, with_headers=True, with_body=True,
|
|||||||
precision.
|
precision.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
chunks = []
|
|
||||||
|
# Output encoding.
|
||||||
|
if env.stdout_isatty:
|
||||||
|
# Use encoding suitable for the terminal. Unsupported characters
|
||||||
|
# will be replaced in the output.
|
||||||
|
errors = 'replace'
|
||||||
|
output_encoding = getattr(env.stdout, 'encoding', None)
|
||||||
|
else:
|
||||||
|
# Preserve the message encoding.
|
||||||
|
errors = 'strict'
|
||||||
|
output_encoding = msg.encoding
|
||||||
|
if not output_encoding:
|
||||||
|
# Default to utf8
|
||||||
|
output_encoding = 'utf8'
|
||||||
|
|
||||||
|
if prettifier:
|
||||||
|
env.init_colors()
|
||||||
|
|
||||||
|
#noinspection PyArgumentList
|
||||||
|
output = bytearray()
|
||||||
|
|
||||||
if with_headers:
|
if with_headers:
|
||||||
headers = '\n'.join([msg.line, msg.headers])
|
headers = '\n'.join([msg.line, msg.headers])
|
||||||
@ -49,37 +68,37 @@ def format(msg, prettifier=None, with_headers=True, with_body=True,
|
|||||||
if prettifier:
|
if prettifier:
|
||||||
headers = prettifier.process_headers(headers)
|
headers = prettifier.process_headers(headers)
|
||||||
|
|
||||||
chunks.append(headers.strip().encode('utf8'))
|
output.extend(
|
||||||
|
headers.encode(output_encoding, errors).strip())
|
||||||
|
|
||||||
if with_body and msg.body or env.stdout_isatty:
|
if with_body and msg.body:
|
||||||
chunks.append(b'\n\n')
|
output.extend(b'\n\n')
|
||||||
|
|
||||||
if with_body and msg.body:
|
if with_body and msg.body:
|
||||||
|
|
||||||
body = msg.body
|
body = msg.body
|
||||||
bin_suppressed = False
|
|
||||||
|
|
||||||
if prettifier or env.stdout_isatty:
|
if not (env.stdout_isatty or prettifier):
|
||||||
|
# Verbatim body even if it's binary.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
body = msg.body.decode(msg.encoding or 'utf8')
|
body = body.decode(msg.encoding)
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
# Assume binary
|
# Suppress binary data.
|
||||||
bin_suppressed = True
|
body = BINARY_SUPPRESSED_NOTICE.encode(output_encoding)
|
||||||
body = BINARY_SUPPRESSED_NOTICE.encode('utf8')
|
|
||||||
if not with_headers:
|
if not with_headers:
|
||||||
body = b'\n' + body
|
output.extend(b'\n')
|
||||||
else:
|
else:
|
||||||
body = body.encode('utf8')
|
if prettifier and msg.content_type:
|
||||||
|
body = prettifier.process_body(
|
||||||
|
body, msg.content_type).strip()
|
||||||
|
|
||||||
if not bin_suppressed and prettifier and msg.content_type:
|
body = body.encode(output_encoding, errors)
|
||||||
body = (prettifier
|
|
||||||
.process_body(body.decode('utf8'), msg.content_type)
|
|
||||||
.strip()
|
|
||||||
.encode('utf8'))
|
|
||||||
|
|
||||||
chunks.append(body)
|
output.extend(body)
|
||||||
|
|
||||||
return b''.join(chunks)
|
return bytes(output)
|
||||||
|
|
||||||
|
|
||||||
class HTTPLexer(lexer.RegexLexer):
|
class HTTPLexer(lexer.RegexLexer):
|
||||||
|
150
tests/tests.py
150
tests/tests.py
@ -45,6 +45,7 @@ from httpie import input
|
|||||||
from httpie.models import Environment
|
from httpie.models import Environment
|
||||||
from httpie.core import main, get_output
|
from httpie.core import main, get_output
|
||||||
from httpie.output import BINARY_SUPPRESSED_NOTICE
|
from httpie.output import BINARY_SUPPRESSED_NOTICE
|
||||||
|
from httpie.input import ParseError
|
||||||
|
|
||||||
|
|
||||||
HTTPBIN_URL = os.environ.get('HTTPBIN_URL',
|
HTTPBIN_URL = os.environ.get('HTTPBIN_URL',
|
||||||
@ -52,7 +53,8 @@ HTTPBIN_URL = os.environ.get('HTTPBIN_URL',
|
|||||||
|
|
||||||
TEST_FILE_PATH = os.path.join(TESTS_ROOT, 'file.txt')
|
TEST_FILE_PATH = os.path.join(TESTS_ROOT, 'file.txt')
|
||||||
TEST_FILE2_PATH = os.path.join(TESTS_ROOT, 'file2.txt')
|
TEST_FILE2_PATH = os.path.join(TESTS_ROOT, 'file2.txt')
|
||||||
TEST_FILE_CONTENT = open(TEST_FILE_PATH).read().strip()
|
with open(TEST_FILE_PATH) as f:
|
||||||
|
TEST_FILE_CONTENT = f.read().strip()
|
||||||
TERMINAL_COLOR_PRESENCE_CHECK = '\x1b['
|
TERMINAL_COLOR_PRESENCE_CHECK = '\x1b['
|
||||||
|
|
||||||
|
|
||||||
@ -89,8 +91,8 @@ def http(*args, **kwargs):
|
|||||||
stdout_isatty=True,
|
stdout_isatty=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
stdout = kwargs['env'].stdout = tempfile.TemporaryFile()
|
stdout = kwargs['env'].stdout = tempfile.TemporaryFile('w+b')
|
||||||
stderr = kwargs['env'].stderr = tempfile.TemporaryFile()
|
stderr = kwargs['env'].stderr = tempfile.TemporaryFile('w+t')
|
||||||
|
|
||||||
exit_status = main(args=['--debug'] + list(args), **kwargs)
|
exit_status = main(args=['--debug'] + list(args), **kwargs)
|
||||||
|
|
||||||
@ -100,8 +102,10 @@ def http(*args, **kwargs):
|
|||||||
output = stdout.read()
|
output = stdout.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
#noinspection PyArgumentList
|
||||||
r = StrResponse(output.decode('utf8'))
|
r = StrResponse(output.decode('utf8'))
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
|
#noinspection PyArgumentList
|
||||||
r = BytesResponse(output)
|
r = BytesResponse(output)
|
||||||
else:
|
else:
|
||||||
if TERMINAL_COLOR_PRESENCE_CHECK not in r:
|
if TERMINAL_COLOR_PRESENCE_CHECK not in r:
|
||||||
@ -120,7 +124,7 @@ def http(*args, **kwargs):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
r.stderr = stderr.read().decode('utf8')
|
r.stderr = stderr.read()
|
||||||
r.exit_status = exit_status
|
r.exit_status = exit_status
|
||||||
|
|
||||||
stdout.close()
|
stdout.close()
|
||||||
@ -133,10 +137,10 @@ class BaseTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
if is_py26:
|
if is_py26:
|
||||||
def assertIn(self, member, container, msg=None):
|
def assertIn(self, member, container, msg=None):
|
||||||
self.assert_(member in container, msg)
|
self.assertTrue(member in container, msg)
|
||||||
|
|
||||||
def assertNotIn(self, member, container, msg=None):
|
def assertNotIn(self, member, container, msg=None):
|
||||||
self.assert_(member not in container, msg)
|
self.assertTrue(member not in container, msg)
|
||||||
|
|
||||||
def assertDictEqual(self, d1, d2, msg=None):
|
def assertDictEqual(self, d1, d2, msg=None):
|
||||||
self.assertEqual(set(d1.keys()), set(d2.keys()), msg)
|
self.assertEqual(set(d1.keys()), set(d2.keys()), msg)
|
||||||
@ -206,19 +210,20 @@ class HTTPieTest(BaseTestCase):
|
|||||||
|
|
||||||
def test_POST_stdin(self):
|
def test_POST_stdin(self):
|
||||||
|
|
||||||
env = Environment(
|
with open(TEST_FILE_PATH) as f:
|
||||||
stdin=open(TEST_FILE_PATH),
|
env = Environment(
|
||||||
stdin_isatty=False,
|
stdin=f,
|
||||||
stdout_isatty=True,
|
stdin_isatty=False,
|
||||||
colors=0,
|
stdout_isatty=True,
|
||||||
)
|
colors=0,
|
||||||
|
)
|
||||||
|
|
||||||
r = http(
|
r = http(
|
||||||
'--form',
|
'--form',
|
||||||
'POST',
|
'POST',
|
||||||
httpbin('/post'),
|
httpbin('/post'),
|
||||||
env=env
|
env=env
|
||||||
)
|
)
|
||||||
self.assertIn('HTTP/1.1 200', r)
|
self.assertIn('HTTP/1.1 200', r)
|
||||||
self.assertIn(TEST_FILE_CONTENT, r)
|
self.assertIn(TEST_FILE_CONTENT, r)
|
||||||
|
|
||||||
@ -434,17 +439,18 @@ class ImplicitHTTPMethodTest(BaseTestCase):
|
|||||||
self.assertIn('"foo": "bar"', r)
|
self.assertIn('"foo": "bar"', r)
|
||||||
|
|
||||||
def test_implicit_POST_stdin(self):
|
def test_implicit_POST_stdin(self):
|
||||||
env = Environment(
|
with open(TEST_FILE_PATH) as f:
|
||||||
stdin_isatty=False,
|
env = Environment(
|
||||||
stdin=open(TEST_FILE_PATH),
|
stdin_isatty=False,
|
||||||
stdout_isatty=True,
|
stdin=f,
|
||||||
colors=0,
|
stdout_isatty=True,
|
||||||
)
|
colors=0,
|
||||||
r = http(
|
)
|
||||||
'--form',
|
r = http(
|
||||||
httpbin('/post'),
|
'--form',
|
||||||
env=env
|
httpbin('/post'),
|
||||||
)
|
env=env
|
||||||
|
)
|
||||||
self.assertIn('HTTP/1.1 200', r)
|
self.assertIn('HTTP/1.1 200', r)
|
||||||
|
|
||||||
|
|
||||||
@ -500,6 +506,7 @@ class VerboseFlagTest(BaseTestCase):
|
|||||||
'test-header:__test__'
|
'test-header:__test__'
|
||||||
)
|
)
|
||||||
self.assertIn('HTTP/1.1 200', r)
|
self.assertIn('HTTP/1.1 200', r)
|
||||||
|
#noinspection PyUnresolvedReferences
|
||||||
self.assertEqual(r.count('__test__'), 2)
|
self.assertEqual(r.count('__test__'), 2)
|
||||||
|
|
||||||
def test_verbose_form(self):
|
def test_verbose_form(self):
|
||||||
@ -524,18 +531,18 @@ class VerboseFlagTest(BaseTestCase):
|
|||||||
'baz=bar'
|
'baz=bar'
|
||||||
)
|
)
|
||||||
self.assertIn('HTTP/1.1 200', r)
|
self.assertIn('HTTP/1.1 200', r)
|
||||||
|
#noinspection PyUnresolvedReferences
|
||||||
self.assertEqual(r.count('"baz": "bar"'), 2)
|
self.assertEqual(r.count('"baz": "bar"'), 2)
|
||||||
|
|
||||||
|
|
||||||
class MultipartFormDataFileUploadTest(BaseTestCase):
|
class MultipartFormDataFileUploadTest(BaseTestCase):
|
||||||
|
|
||||||
def test_non_existent_file_raises_parse_error(self):
|
def test_non_existent_file_raises_parse_error(self):
|
||||||
self.assertRaises(SystemExit, http,
|
self.assertRaises(ParseError, http,
|
||||||
'--form',
|
'--form',
|
||||||
'--traceback',
|
|
||||||
'POST',
|
'POST',
|
||||||
httpbin('/post'),
|
httpbin('/post'),
|
||||||
'foo@/__does_not_exist__'
|
'foo@/__does_not_exist__',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_upload_ok(self):
|
def test_upload_ok(self):
|
||||||
@ -552,6 +559,7 @@ class MultipartFormDataFileUploadTest(BaseTestCase):
|
|||||||
self.assertIn('Content-Disposition: form-data; name="foo"', r)
|
self.assertIn('Content-Disposition: form-data; name="foo"', r)
|
||||||
self.assertIn('Content-Disposition: form-data; name="test-file";'
|
self.assertIn('Content-Disposition: form-data; name="test-file";'
|
||||||
' filename="%s"' % os.path.basename(TEST_FILE_PATH), r)
|
' filename="%s"' % os.path.basename(TEST_FILE_PATH), r)
|
||||||
|
#noinspection PyUnresolvedReferences
|
||||||
self.assertEqual(r.count(TEST_FILE_CONTENT), 2)
|
self.assertEqual(r.count(TEST_FILE_CONTENT), 2)
|
||||||
self.assertIn('"foo": "bar"', r)
|
self.assertIn('"foo": "bar"', r)
|
||||||
|
|
||||||
@ -620,19 +628,38 @@ class RequestBodyFromFilePathTest(BaseTestCase):
|
|||||||
self.assertIn('"Content-Type": "x-foo/bar"', r)
|
self.assertIn('"Content-Type": "x-foo/bar"', r)
|
||||||
|
|
||||||
def test_request_body_from_file_by_path_no_field_name_allowed(self):
|
def test_request_body_from_file_by_path_no_field_name_allowed(self):
|
||||||
self.assertRaises(SystemExit, lambda: http(
|
env = Environment(stdin_isatty=True)
|
||||||
'POST',
|
try:
|
||||||
httpbin('/post'),
|
http(
|
||||||
'field-name@' + TEST_FILE_PATH)
|
'POST',
|
||||||
)
|
httpbin('/post'),
|
||||||
|
'field-name@' + TEST_FILE_PATH,
|
||||||
|
env=env
|
||||||
|
)
|
||||||
|
except SystemExit:
|
||||||
|
env.stderr.seek(0)
|
||||||
|
stderr = env.stderr.read()
|
||||||
|
self.assertIn('perhaps you meant --form?', stderr)
|
||||||
|
else:
|
||||||
|
self.fail('validation did not work')
|
||||||
|
|
||||||
def test_request_body_from_file_by_path_no_data_items_allowed(self):
|
def test_request_body_from_file_by_path_no_data_items_allowed(self):
|
||||||
self.assertRaises(SystemExit, lambda: http(
|
env = Environment(stdin_isatty=True)
|
||||||
'POST',
|
try:
|
||||||
httpbin('/post'),
|
http(
|
||||||
'@' + TEST_FILE_PATH,
|
'POST',
|
||||||
'foo=bar')
|
httpbin('/post'),
|
||||||
)
|
'@' + TEST_FILE_PATH,
|
||||||
|
'foo=bar',
|
||||||
|
env=env
|
||||||
|
)
|
||||||
|
except SystemExit:
|
||||||
|
env.stderr.seek(0)
|
||||||
|
self.assertIn(
|
||||||
|
'cannot be mixed',
|
||||||
|
env.stderr.read())
|
||||||
|
else:
|
||||||
|
self.fail('validation did not work')
|
||||||
|
|
||||||
|
|
||||||
class AuthTest(BaseTestCase):
|
class AuthTest(BaseTestCase):
|
||||||
@ -727,7 +754,7 @@ class ExitStatusTest(BaseTestCase):
|
|||||||
self.assertIn('HTTP/1.1 401', r)
|
self.assertIn('HTTP/1.1 401', r)
|
||||||
self.assertEqual(r.exit_status, 4)
|
self.assertEqual(r.exit_status, 4)
|
||||||
# Also stderr should be empty since stdout isn't redirected.
|
# Also stderr should be empty since stdout isn't redirected.
|
||||||
self.assert_(not r.stderr)
|
self.assertTrue(not r.stderr)
|
||||||
|
|
||||||
def test_5xx_check_status_exits_5(self):
|
def test_5xx_check_status_exits_5(self):
|
||||||
r = http(
|
r = http(
|
||||||
@ -739,6 +766,41 @@ class ExitStatusTest(BaseTestCase):
|
|||||||
self.assertEqual(r.exit_status, 5)
|
self.assertEqual(r.exit_status, 5)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeWindowsTest(BaseTestCase):
|
||||||
|
|
||||||
|
def test_stdout_redirect_not_supported_on_windows(self):
|
||||||
|
env = Environment(is_windows=True, stdout_isatty=False)
|
||||||
|
r = http(
|
||||||
|
'GET',
|
||||||
|
httpbin('/get'),
|
||||||
|
env=env
|
||||||
|
)
|
||||||
|
self.assertNotEqual(r.exit_status, 0)
|
||||||
|
self.assertIn('Windows', r.stderr)
|
||||||
|
self.assertIn('--output', r.stderr)
|
||||||
|
|
||||||
|
def test_output_file_pretty_not_allowed_on_windows(self):
|
||||||
|
env = Environment(
|
||||||
|
is_windows=True, stdout_isatty=True, stdin_isatty=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
http(
|
||||||
|
'--output',
|
||||||
|
os.path.join(tempfile.gettempdir(), '__httpie_test_output__'),
|
||||||
|
'--pretty',
|
||||||
|
'GET',
|
||||||
|
httpbin('/get'),
|
||||||
|
env=env
|
||||||
|
)
|
||||||
|
except SystemExit:
|
||||||
|
env.stderr.seek(0)
|
||||||
|
err = env.stderr.read()
|
||||||
|
self.assertIn(
|
||||||
|
'Only terminal output can be prettified on Windows', err)
|
||||||
|
else:
|
||||||
|
self.fail('validation did not work')
|
||||||
|
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
# CLI argument parsing related tests.
|
# CLI argument parsing related tests.
|
||||||
#################################################################
|
#################################################################
|
||||||
|
Loading…
x
Reference in New Issue
Block a user