mirror of
https://github.com/httpie/cli.git
synced 2025-06-04 23:27:28 +02:00
parent
85b3a016eb
commit
681b652bf9
24
README.rst
24
README.rst
@ -118,6 +118,7 @@ Flags
|
|||||||
^^^^^
|
^^^^^
|
||||||
Most of the flags mirror the arguments understood by ``requests.request``. See ``http -h`` for more details::
|
Most of the flags mirror the arguments understood by ``requests.request``. See ``http -h`` for more details::
|
||||||
|
|
||||||
|
$ http --help
|
||||||
usage: http [-h] [--version] [--json | --form] [--traceback]
|
usage: http [-h] [--version] [--json | --form] [--traceback]
|
||||||
[--pretty | --ugly]
|
[--pretty | --ugly]
|
||||||
[--print OUTPUT_OPTIONS | --verbose | --headers | --body]
|
[--print OUTPUT_OPTIONS | --verbose | --headers | --body]
|
||||||
@ -147,13 +148,15 @@ Most of the flags mirror the arguments understood by ``requests.request``. See `
|
|||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
--version show program's version number and exit
|
--version show program's version number and exit
|
||||||
--json, -j (default) Data items are serialized as a JSON object.
|
--json, -j (default) Data items from the command line are
|
||||||
The Content-Type and Accept headers are set to
|
serialized as a JSON object. The Content-Type and
|
||||||
application/json (if not set via the command line).
|
Accept headers are set to application/json (if not
|
||||||
--form, -f Data items are serialized as form fields. The Content-
|
specified).
|
||||||
Type is set to application/x-www-form-urlencoded (if
|
--form, -f Data items from the command line are serialized as
|
||||||
not specifid). The presence of any file fields results
|
form fields. The Content-Type is set to application/x
|
||||||
into a multipart/form-data request.
|
-www-form-urlencoded (if not specified). The presence
|
||||||
|
of any file fields results into a multipart/form-data
|
||||||
|
request.
|
||||||
--traceback Print exception traceback should one occur.
|
--traceback Print exception traceback should one occur.
|
||||||
--pretty If stdout is a terminal, the response is prettified by
|
--pretty If stdout is a terminal, the response is prettified by
|
||||||
default (colorized and indented if it is JSON). This
|
default (colorized and indented if it is JSON). This
|
||||||
@ -180,8 +183,8 @@ Most of the flags mirror the arguments understood by ``requests.request``. See `
|
|||||||
make sure that the $TERM environment variable is set
|
make sure that the $TERM environment variable is set
|
||||||
to "xterm-256color" or similar (e.g., via `export TERM
|
to "xterm-256color" or similar (e.g., via `export TERM
|
||||||
=xterm-256color' in your ~/.bashrc).
|
=xterm-256color' in your ~/.bashrc).
|
||||||
--auth AUTH, -a AUTH username:password. If the password is omitted, HTTPie
|
--auth AUTH, -a AUTH username:password. If the password is omitted (-a
|
||||||
will prompt for it.
|
username), HTTPie will prompt for it.
|
||||||
--auth-type {basic,digest}
|
--auth-type {basic,digest}
|
||||||
The authentication mechanism to be used. Defaults to
|
The authentication mechanism to be used. Defaults to
|
||||||
"basic".
|
"basic".
|
||||||
@ -223,7 +226,10 @@ Changelog
|
|||||||
---------
|
---------
|
||||||
|
|
||||||
* `0.2.3dev <https://github.com/jkbr/httpie/compare/0.2.2...master>`_
|
* `0.2.3dev <https://github.com/jkbr/httpie/compare/0.2.2...master>`_
|
||||||
|
* --auth now prompts for a password if none is provided.
|
||||||
* Added support for request payloads from a file path with automatic ``Content-Type`` (``http URL @/path``).
|
* Added support for request payloads from a file path with automatic ``Content-Type`` (``http URL @/path``).
|
||||||
|
* Fixed missing query string when displaing the request headers via ``--verbose``.
|
||||||
|
* Fixed Content-Type for requests with no data.
|
||||||
* `0.2.2 <https://github.com/jkbr/httpie/compare/0.2.1...0.2.2>`_ (2012-06-24)
|
* `0.2.2 <https://github.com/jkbr/httpie/compare/0.2.1...0.2.2>`_ (2012-06-24)
|
||||||
* The ``METHOD`` positional argument can now be omitted (defaults to ``GET``, or to ``POST`` with data).
|
* The ``METHOD`` positional argument can now be omitted (defaults to ``GET``, or to ``POST`` with data).
|
||||||
* Fixed --verbose --form.
|
* Fixed --verbose --form.
|
||||||
|
@ -123,10 +123,10 @@ parser.add_argument(
|
|||||||
|
|
||||||
# ``requests.request`` keyword arguments.
|
# ``requests.request`` keyword arguments.
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--auth', '-a', type=cliparse.AuthCredentials(cliparse.SEP_COMMON),
|
'--auth', '-a', type=cliparse.AuthCredentialsType(cliparse.SEP_COMMON),
|
||||||
help=_('''
|
help=_('''
|
||||||
username:password.
|
username:password.
|
||||||
If the password is omitted, HTTPie will prompt for it.
|
If the password is omitted (-a username), HTTPie will prompt for it.
|
||||||
'''),
|
'''),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,9 +8,7 @@ import re
|
|||||||
import json
|
import json
|
||||||
import argparse
|
import argparse
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
import getpass
|
||||||
from collections import namedtuple
|
|
||||||
from getpass import getpass
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
@ -54,13 +52,22 @@ class Parser(argparse.ArgumentParser):
|
|||||||
def parse_args(self, args=None, namespace=None,
|
def parse_args(self, args=None, namespace=None,
|
||||||
stdin=sys.stdin,
|
stdin=sys.stdin,
|
||||||
stdin_isatty=sys.stdin.isatty()):
|
stdin_isatty=sys.stdin.isatty()):
|
||||||
|
|
||||||
args = super(Parser, self).parse_args(args, namespace)
|
args = super(Parser, self).parse_args(args, namespace)
|
||||||
|
|
||||||
self._validate_output_options(args)
|
self._validate_output_options(args)
|
||||||
self._validate_auth_options(args)
|
self._validate_auth_options(args)
|
||||||
self._guess_method(args, stdin_isatty)
|
self._guess_method(args, stdin_isatty)
|
||||||
self._parse_items(args)
|
self._parse_items(args)
|
||||||
|
|
||||||
if not stdin_isatty:
|
if not stdin_isatty:
|
||||||
self._body_from_file(args, stdin)
|
self._body_from_file(args, stdin)
|
||||||
|
|
||||||
|
if args.auth and not args.auth.has_password():
|
||||||
|
# stdin has already been read (if not a tty) so
|
||||||
|
# it's save to prompt now.
|
||||||
|
args.auth.prompt_password()
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def _body_from_file(self, args, f):
|
def _body_from_file(self, args, f):
|
||||||
@ -161,12 +168,24 @@ class ParseError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
KeyValue = namedtuple('KeyValue', ['key', 'value', 'sep', 'orig'])
|
class KeyValue(object):
|
||||||
|
"""Base key-value pair parsed from CLI."""
|
||||||
|
|
||||||
|
def __init__(self, key, value, sep, orig):
|
||||||
|
self.key = key
|
||||||
|
self.value = value
|
||||||
|
self.sep = sep
|
||||||
|
self.orig = orig
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.__dict__ == other.__dict__
|
||||||
|
|
||||||
|
|
||||||
class KeyValueType(object):
|
class KeyValueType(object):
|
||||||
"""A type used with `argparse`."""
|
"""A type used with `argparse`."""
|
||||||
|
|
||||||
|
key_value_class = KeyValue
|
||||||
|
|
||||||
def __init__(self, *separators):
|
def __init__(self, *separators):
|
||||||
self.separators = separators
|
self.separators = separators
|
||||||
self.escapes = ['\\\\' + sep for sep in separators]
|
self.escapes = ['\\\\' + sep for sep in separators]
|
||||||
@ -202,21 +221,43 @@ class KeyValueType(object):
|
|||||||
for sepstr in self.separators:
|
for sepstr in self.separators:
|
||||||
key = key.replace('\\' + sepstr, sepstr)
|
key = key.replace('\\' + sepstr, sepstr)
|
||||||
value = value.replace('\\' + sepstr, sepstr)
|
value = value.replace('\\' + sepstr, sepstr)
|
||||||
return KeyValue(key=key, value=value, sep=sep, orig=string)
|
return self.key_value_class(key=key, value=value, sep=sep, orig=string)
|
||||||
|
|
||||||
|
|
||||||
class AuthCredentials(KeyValueType):
|
class AuthCredentials(KeyValue):
|
||||||
def __call__(self, string):
|
"""
|
||||||
|
Represents parsed credentials.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def _getpass(self, prompt):
|
||||||
|
return getpass.getpass(prompt)
|
||||||
|
|
||||||
|
def has_password(self):
|
||||||
|
return self.value is not None
|
||||||
|
|
||||||
|
def prompt_password(self):
|
||||||
try:
|
try:
|
||||||
return super(AuthCredentials, self).__call__(string)
|
self.value = self._getpass("Password for user '%s': " % self.key)
|
||||||
except argparse.ArgumentTypeError:
|
|
||||||
try:
|
|
||||||
password = getpass("Password for user '%s': " % string)
|
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
sys.stderr.write('\n')
|
sys.stderr.write('\n')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return KeyValue(key=string, value=password, sep=SEP_COMMON,
|
|
||||||
orig=string)
|
|
||||||
|
class AuthCredentialsType(KeyValueType):
|
||||||
|
|
||||||
|
key_value_class = AuthCredentials
|
||||||
|
|
||||||
|
def __call__(self, string):
|
||||||
|
try:
|
||||||
|
return super(AuthCredentialsType, self).__call__(string)
|
||||||
|
except argparse.ArgumentTypeError:
|
||||||
|
# No password provided, will prompt for it later.
|
||||||
|
return self.key_value_class(
|
||||||
|
key=string,
|
||||||
|
value=None,
|
||||||
|
sep=SEP_COMMON,
|
||||||
|
orig=string
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_items(items, data=None, headers=None, files=None):
|
def parse_items(items, data=None, headers=None, files=None):
|
||||||
|
@ -286,6 +286,16 @@ class AuthTest(BaseTestCase):
|
|||||||
self.assertIn('"authenticated": true', r)
|
self.assertIn('"authenticated": true', r)
|
||||||
self.assertIn('"user": "user"', r)
|
self.assertIn('"user": "user"', r)
|
||||||
|
|
||||||
|
def test_password_prompt(self):
|
||||||
|
cliparse.AuthCredentials._getpass = lambda self, prompt: 'password'
|
||||||
|
|
||||||
|
r = http('--auth', 'user',
|
||||||
|
'GET', 'httpbin.org/basic-auth/user/password')
|
||||||
|
|
||||||
|
self.assertIn('HTTP/1.1 200', r)
|
||||||
|
self.assertIn('"authenticated": true', r)
|
||||||
|
self.assertIn('"user": "user"', r)
|
||||||
|
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
# CLI argument parsing related tests.
|
# CLI argument parsing related tests.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user