This commit is contained in:
Jakub Roztocil 2012-09-21 05:43:34 +02:00
parent a41dd7ac6d
commit e25d64a610
7 changed files with 64 additions and 53 deletions

View File

@ -1,8 +1,8 @@
***********************
HTTPie: cURL for Humans
***********************
****************************************
HTTPie: a CLI, cURL-like tool for humans
****************************************
v0.2.8-alpha (`stable version`_)
v0.3.0
HTTPie is a **command line HTTP client** whose goal is to make CLI interaction
with web services as **human-friendly** as possible. It provides a
@ -42,6 +42,7 @@ Main Features
* HTTPS, proxies, and authentication
* Arbitrary request data
* Custom headers
* Persistent sessions
* Python 2.6, 2.7 and 3.x support
* Linux, Mac OS X and Windows support
* Documentation
@ -825,34 +826,35 @@ Streamed output by small chunks alá ``tail -f``:
Sessions
========
HTTPie supports named, per-host sessions, where custom headers, authorization,
and cookies (manually specified or sent by the server) persist between requests:
By default, every request is completely independent of the previous ones.
HTTPie supports persistent sessions, where custom headers, authorization,
and cookies (manually specified or sent by the server) persist between
requests. Sessions are named and host-bound.
Create a new session named ``user1``:
.. code-block:: bash
$ http --session user1 -a user1:password example.org X-Foo:Bar
$ http --session=user1 -a user1:password example.org X-Foo:Bar
Now you can refer to the session by its name:
.. code-block:: bash
$ http --session user1 example.org
$ http --session=user1 example.org
To switch to another session simple pass a different name:
To create or reuse a different session, simple specify a different name:
.. code-block:: bash
$ http --session user2 -a user2:password example.org X-Bar:Foo
$ http --session=user2 -a user2:password example.org X-Bar:Foo
To use a session without updating it from the request/response exchange
once it is created, specify the session name via
``--session-read-only=SESSION_NAME`` instead.
You can view and manipulate existing sessions via the ``httpie`` management
command, see ``httpie --help``.
Sessions are stored as JSON in ``~/.httpie/sessions/<host>/<name>.json``
Sessions are stored as JSON files in ``~/.httpie/sessions/<host>/<name>.json``
(``%APPDATA%\httpie\sessions\<host>\<name>.json`` on Windows).
See also `config`_.
@ -862,8 +864,8 @@ See also `config`_.
Config
======
HTTPie provides a simple configuration file containing a JSON
object with the following keys:
HTTPie uses a simple configuration file that contains a JSON object with the
following keys:
========================= =================================================
``__version__`` HTTPie automatically sets this to its version.
@ -1025,9 +1027,9 @@ Changelog
*You can click a version name to see a diff with the previous one.*
* `0.2.8-alpha`_
* `0.3.0`_ (2012-09-21)
* Allow output redirection on Windows.
* Added config file.
* Added configuration file.
* Added persistent session support.
* Renamed ``--allow-redirects`` to ``--follow``.
* Improved the usability of ``http --help``.
@ -1117,7 +1119,7 @@ Changelog
.. _0.2.5: https://github.com/jkbr/httpie/compare/0.2.2...0.2.5
.. _0.2.6: https://github.com/jkbr/httpie/compare/0.2.5...0.2.6
.. _0.2.7: https://github.com/jkbr/httpie/compare/0.2.5...0.2.7
.. _0.2.8-alpha: https://github.com/jkbr/httpie/compare/0.2.7...master
.. _stable version: https://github.com/jkbr/httpie/tree/0.2.7#readme
.. _0.3.0: https://github.com/jkbr/httpie/compare/0.2.7...0.3.0
.. _stable version: https://github.com/jkbr/httpie/tree/0.3.0#readme
.. _AUTHORS.rst: https://github.com/jkbr/httpie/blob/master/AUTHORS.rst
.. _LICENSE: https://github.com/jkbr/httpie/blob/master/LICENSE

View File

@ -1,13 +1,13 @@
"""
HTTPie - cURL for humans.
HTTPie - a CLI, cURL-like tool for humans.
"""
__author__ = 'Jakub Roztocil'
__version__ = '0.2.8-alpha'
__version__ = '0.3.0'
__licence__ = 'BSD'
class EXIT:
class exit:
OK = 0
ERROR = 1
ERROR_TIMEOUT = 2

View File

@ -1,6 +1,8 @@
"""CLI arguments definition.
NOTE: the CLI interface may change before reaching v1.0.
TODO: make the options config friendly, i.e., no mutually exclusive groups to
allow options overwriting.
"""
from argparse import FileType, OPTIONAL, ZERO_OR_MORE, SUPPRESS
@ -9,7 +11,7 @@ from requests.compat import is_windows
from . import __doc__
from . import __version__
from .config import DEFAULT_CONFIG_DIR
from .sessions import DEFAULT_SESSIONS_DIR
from .output import AVAILABLE_STYLES, DEFAULT_STYLE
from .input import (Parser, AuthCredentialsArgType, KeyValueArgType,
SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ITEMS,
@ -231,14 +233,14 @@ sessions.add_argument(
Create, or reuse and update a session.
Withing a session, custom headers, auth credential, as well as any
cookies sent by the server persist between requests.
You can use the `httpie' management command to manipulate
and inspect existing sessions. See `httpie --help'.
''')
Session files are stored in %s/<HOST>/<SESSION_NAME>.json.
''' % DEFAULT_SESSIONS_DIR)
)
sessions.add_argument(
'--session-read-only', metavar='SESSION_NAME',
help=_('''
Create or reuse a session, but do not update it once saved.
Create or read a session without updating it form the
request/response exchange.
''')
)

View File

@ -23,22 +23,22 @@ from .cli import parser
from .client import get_response
from .models import Environment
from .output import output_stream, write, write_with_colors_win_p3k
from . import EXIT
from . import exit
def get_exist_status(code, follow=False):
"""Translate HTTP status code to exit status."""
if 300 <= code <= 399 and not follow:
# Redirect
return EXIT.ERROR_HTTP_3XX
return exit.ERROR_HTTP_3XX
elif 400 <= code <= 499:
# Client Error
return EXIT.ERROR_HTTP_4XX
return exit.ERROR_HTTP_4XX
elif 500 <= code <= 599:
# Server Error
return EXIT.ERROR_HTTP_5XX
return exit.ERROR_HTTP_5XX
else:
return EXIT.OK
return exit.OK
def print_debug_info(env):
@ -66,12 +66,12 @@ def main(args=sys.argv[1:], env=Environment()):
debug = '--debug' in args
traceback = debug or '--traceback' in args
status = EXIT.OK
status = exit.OK
if debug:
print_debug_info(env)
if args == ['--debug']:
sys.exit(EXIT.OK)
sys.exit(exit.OK)
try:
args = parser.parse_args(args=args, env=env)
@ -108,9 +108,9 @@ def main(args=sys.argv[1:], env=Environment()):
if traceback:
raise
env.stderr.write('\n')
status = EXIT.ERROR
status = exit.ERROR
except requests.Timeout:
status = EXIT.ERROR_TIMEOUT
status = exit.ERROR_TIMEOUT
error('Request timed out (%ss).', args.timeout)
except Exception as e:
# TODO: distinguish between expected and unexpected errors.
@ -118,6 +118,6 @@ def main(args=sys.argv[1:], env=Environment()):
if traceback:
raise
error('%s: %s', type(e).__name__, str(e))
status = EXIT.ERROR
status = exit.ERROR
return status

View File

@ -20,6 +20,7 @@ from .output import PygmentsProcessor
SESSIONS_DIR_NAME = 'sessions'
DEFAULT_SESSIONS_DIR = os.path.join(DEFAULT_CONFIG_DIR, SESSIONS_DIR_NAME)
def get_response(name, request_kwargs, config_dir, read_only=False):
@ -92,8 +93,8 @@ class Host(object):
@classmethod
def all(cls):
"""Return a generator yielding a host at a time."""
for name in sorted(glob.glob1(SESSIONS_DIR, '*')):
if os.path.isdir(os.path.join(SESSIONS_DIR, name)):
for name in sorted(glob.glob1(DEFAULT_SESSIONS_DIR, '*')):
if os.path.isdir(os.path.join(DEFAULT_SESSIONS_DIR, name)):
yield Host(name)
@ -156,6 +157,9 @@ class Session(BaseConfigDict):
}
# The commands are disabled for now.
# TODO: write tests for the commands.
def list_command(args):
if args.host:
for name, path in Host(args.host):

View File

@ -47,7 +47,8 @@ setup(
entry_points={
'console_scripts': [
'http = httpie.__main__:main',
'httpie = httpie.manage:main',
# Not ready yet.
# 'httpie = httpie.manage:main',
],
},
install_requires=requirements,

View File

@ -19,6 +19,7 @@ To make it run faster and offline you can::
HTTPBIN_URL=http://localhost:5000 tox
"""
from functools import partial
import subprocess
import os
import sys
@ -28,6 +29,7 @@ import tempfile
import unittest
import shutil
from requests.compat import urlparse
try:
from urllib.request import urlopen
except ImportError:
@ -55,7 +57,7 @@ from requests.compat import is_windows, is_py26, bytes, str
TESTS_ROOT = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.realpath(os.path.join(TESTS_ROOT, '..')))
from httpie import EXIT
from httpie import exit
from httpie import input
from httpie.models import Environment
from httpie.core import main
@ -183,7 +185,7 @@ def http(*args, **kwargs):
sys.stderr.write(env.stderr.read())
raise
except SystemExit:
exit_status = EXIT.ERROR
exit_status = exit.ERROR
env.stdout.seek(0)
env.stderr.seek(0)
@ -865,7 +867,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/200')
)
self.assertIn(OK, r)
self.assertEqual(r.exit_status, EXIT.OK)
self.assertEqual(r.exit_status, exit.OK)
def test_error_response_exits_0_without_check_status(self):
r = http(
@ -873,7 +875,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/500')
)
self.assertIn('HTTP/1.1 500', r)
self.assertEqual(r.exit_status, EXIT.OK)
self.assertEqual(r.exit_status, exit.OK)
self.assertTrue(not r.stderr)
def test_timeout_exit_status(self):
@ -882,7 +884,7 @@ class ExitStatusTest(BaseTestCase):
'GET',
httpbin('/delay/1')
)
self.assertEqual(r.exit_status, EXIT.ERROR_TIMEOUT)
self.assertEqual(r.exit_status, exit.ERROR_TIMEOUT)
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(self):
r = http(
@ -893,7 +895,7 @@ class ExitStatusTest(BaseTestCase):
env=TestEnvironment(stdout_isatty=False,)
)
self.assertIn('HTTP/1.1 301', r)
self.assertEqual(r.exit_status, EXIT.ERROR_HTTP_3XX)
self.assertEqual(r.exit_status, exit.ERROR_HTTP_3XX)
self.assertIn('301 moved permanently', r.stderr.lower())
@skipIf(requests_version == '0.13.6',
@ -907,7 +909,7 @@ class ExitStatusTest(BaseTestCase):
)
# The redirect will be followed so 200 is expected.
self.assertIn('HTTP/1.1 200 OK', r)
self.assertEqual(r.exit_status, EXIT.OK)
self.assertEqual(r.exit_status, exit.OK)
def test_4xx_check_status_exits_4(self):
r = http(
@ -916,7 +918,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/401')
)
self.assertIn('HTTP/1.1 401', r)
self.assertEqual(r.exit_status, EXIT.ERROR_HTTP_4XX)
self.assertEqual(r.exit_status, exit.ERROR_HTTP_4XX)
# Also stderr should be empty since stdout isn't redirected.
self.assertTrue(not r.stderr)
@ -927,7 +929,7 @@ class ExitStatusTest(BaseTestCase):
httpbin('/status/500')
)
self.assertIn('HTTP/1.1 500', r)
self.assertEqual(r.exit_status, EXIT.ERROR_HTTP_5XX)
self.assertEqual(r.exit_status, exit.ERROR_HTTP_5XX)
class WindowsOnlyTests(BaseTestCase):
@ -1267,7 +1269,7 @@ class SessionTest(BaseTestCase):
shutil.rmtree(self.config_dir)
def test_session_create(self):
# Verify that the has been created
# Verify that the session has been created.
r = http(
'--session=test',
'GET',
@ -1316,7 +1318,7 @@ class SessionTest(BaseTestCase):
self.assertNotEqual(r1.json['headers']['Authorization'],
r3.json['headers']['Authorization'])
def test_session_only(self):
def test_session_read_only(self):
# Get a response from the original session.
r1 = http(
'--session=test',