diff --git a/README.rst b/README.rst index 1fe59f6f..f1a5c229 100644 --- a/README.rst +++ b/README.rst @@ -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//.json`` +Sessions are stored as JSON files in ``~/.httpie/sessions//.json`` (``%APPDATA%\httpie\sessions\\.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 diff --git a/httpie/__init__.py b/httpie/__init__.py index 42cc96fa..cf1e61ad 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -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 diff --git a/httpie/cli.py b/httpie/cli.py index d16f67b6..01437500 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -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//.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. ''') ) diff --git a/httpie/core.py b/httpie/core.py index fa93ef88..b72b896c 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -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 diff --git a/httpie/sessions.py b/httpie/sessions.py index 4f1b4307..0287c922 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -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): diff --git a/setup.py b/setup.py index 305e2415..b3f08f5b 100644 --- a/setup.py +++ b/setup.py @@ -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, diff --git a/tests/tests.py b/tests/tests.py index c5c8f12c..c3390762 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -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',