diff --git a/AUTHORS.rst b/AUTHORS.rst index 1d7437d6..684fe8be 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -33,3 +33,4 @@ Patches and ideas * `Matthias Lehmann `_ * `Dennis Brakhane `_ * `Matt Layman `_ +* `Edward Yang `_ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 57309232..961f0375 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,13 +5,20 @@ Change Log This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. - `1.0.0-dev`_ (Unreleased) ------------------------- + +`0.9.3`_ (2016-01-01) +------------------------- + * Changed the default color ``--style`` from ``solarized`` to ``monokai`` -* Added Bash auto complete support +* Added basic Bash autocomplete support (need to be installed manually) * Added request details to connection error messages +* Fixed ``'requests.packages.urllib3' has no attribute 'disable_warnings'`` + errors that occurred in some installations +* Fixed colors and formatting on Windows +* Fixed ``--auth`` prompt on Windows `0.9.2`_ (2015-02-24) @@ -252,4 +259,5 @@ This project adheres to `Semantic Versioning `_. .. _0.9.0: https://github.com/jkbrzt/httpie/compare/0.8.0...0.9.0 .. _0.9.1: https://github.com/jkbrzt/httpie/compare/0.9.0...0.9.1 .. _0.9.2: https://github.com/jkbrzt/httpie/compare/0.9.1...0.9.2 -.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.2...master +.. _0.9.3: https://github.com/jkbrzt/httpie/compare/0.9.2...0.9.3 +.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.3...master diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index b5052b31..ca57350d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,12 +1,13 @@ +###################### Contributing to HTTPie ###################### -Bug reports and code and documentation patches are greatly appretiated. You can -also help by using the development version of HTTPie and reporting any bugs you -might encounter. +Bug reports and code and documentation patches are welcome. You can +help this project also by using the development version of HTTPie +and by reporting any bugs you might encounter. -Bug Reports -=========== +1. Reporting bugs +================= **It's important that you provide the full command argument list as well as the output of the failing command.** @@ -15,12 +16,12 @@ to your bug report, e.g.: .. code-block:: bash - $ http --debug [arguments that trigger the error] - [complete output] + $ http --debug [COMPLETE ARGUMENT LIST THAT TRIGGERS THE ERROR] + [COMPLETE OUTPUT] -Contributing Code and Documentation -=================================== +2. Contributing Code and Docs +============================= Before working on a new feature or a bug, please browse `existing issues`_ to see whether it has been previously discussed. If the change in question @@ -28,8 +29,11 @@ is a bigger one, it's always good to discuss before your starting working on it. -Development Environment ------------------------ +Creating Development Environment +-------------------------------- + +Go to https://github.com/jkbrzt/httpie and fork the project repository. + .. code-block:: bash @@ -52,44 +56,61 @@ Making Changes Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8). -Tests ------ +Testing +------- Before opening a pull requests, please make sure the `test suite`_ passes -in all of the `supported Python environments`_. You should also **add tests -for any new features and bug fixes**. +in all of the `supported Python environments`_. You should also add tests +for any new features and bug fixes. -HTTPie uses `pytest`_ and `Tox`_. +HTTPie uses `pytest`_ and `Tox`_ for testing. + + +Running all tests: +****************** .. code-block:: bash - ### Running all tests: - - # Current Python + # Run all tests on the current Python interpreter make test - # Current Python with coverage + # Run all tests on the current Python with coverage make test-cover - # All the supported and available Pythons via Tox + # Run all tests in all of the supported and available Pythons via Tox make test-tox - ### Running specific tests: + # Run all tests for code as well as packaging, etc. + make test-all - # Current Python - pytest tests/test_uploads.py - # All Pythons +Running specific tests: +*********************** + +.. code-block:: bash + + # Run specific tests on the current Python + py.test tests/test_uploads.py + py.test tests/test_uploads.py::TestMultipartFormDataFileUpload + py.test tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok + + # Run specific tests on the on all Pythons via Tox tox -- tests/test_uploads.py --verbose + tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload --verbose + tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok --verbose -Don't forget to add yourself to `AUTHORS.rst`_. +----- + +See `Makefile`_ for additional development utilities. +Don't forget to add yourself to `AUTHORS`_! .. _Tox: http://tox.testrun.org .. _supported Python environments: https://github.com/jkbrzt/httpie/blob/master/tox.ini .. _existing issues: https://github.com/jkbrzt/httpie/issues?state=open -.. _AUTHORS.rst: https://github.com/jkbrzt/httpie/blob/master/AUTHORS.rst +.. _AUTHORS: https://github.com/jkbrzt/httpie/blob/master/AUTHORS.rst +.. _Makefile: https://github.com/jkbrzt/httpie/blob/master/Makefile .. _pytest: http://pytest.org/ .. _Style Guide for Python Code: http://python.org/dev/peps/pep-0008/ .. _test suite: https://github.com/jkbrzt/httpie/tree/master/tests diff --git a/LICENSE b/LICENSE index e3b1fc82..b84d413a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012-2015 Jakub Roztocil +Copyright © 2012-2016 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/Makefile b/Makefile index 26b65083..89e0342e 100644 --- a/Makefile +++ b/Makefile @@ -1,39 +1,42 @@ +# +# See ./CONTRIBUTING.rst +# + VERSION=$(shell grep __version__ httpie/__init__.py) REQUIREMENTS="requirements-dev.txt" TAG="\n\n\033[0;32m\#\#\# " END=" \#\#\# \033[0m\n" + all: test -uninstall-httpie: - @echo $(TAG)Removing existing installation of HTTPie$(END) - - pip uninstall --yes httpie >/dev/null - ! which http - @echo - -uninstall-all: uninstall-httpie - - pip uninstall --yes -r $(REQUIREMENTS) init: uninstall-httpie @echo $(TAG)Installing dev requirements$(END) pip install --upgrade -r $(REQUIREMENTS) + @echo $(TAG)Installing HTTPie$(END) pip install --upgrade --editable . + @echo + test: init - @echo $(TAG)Running tests in on current Python with coverage $(END) + @echo $(TAG)Running tests on the current Python interpreter with coverage $(END) py.test --cov ./httpie --cov ./tests --doctest-modules --verbose ./httpie ./tests @echo + test-tox: init @echo $(TAG)Running tests on all Pythons via Tox$(END) tox @echo + test-dist: test-sdist test-bdist-wheel @echo + test-sdist: clean uninstall-httpie @echo $(TAG)Testing sdist build an installation$(END) python setup.py sdist @@ -41,6 +44,7 @@ test-sdist: clean uninstall-httpie which http @echo + test-bdist-wheel: clean uninstall-httpie @echo $(TAG)Testing wheel build an installation$(END) python setup.py bdist_wheel @@ -48,9 +52,11 @@ test-bdist-wheel: clean uninstall-httpie which http @echo + # This tests everything, even this Makefile. test-all: uninstall-all clean init test test-tox test-dist + publish: test-all @echo $(TAG)Testing wheel build an installation$(END) @echo "$(VERSION)" @@ -60,8 +66,29 @@ publish: test-all python setup.py bdist_wheel upload @echo + clean: @echo $(TAG)Cleaning up$(END) rm -rf .tox *.egg dist build .coverage find . -name '__pycache__' -delete -print -o -name '*.pyc' -delete -print @echo + + +uninstall-httpie: + @echo $(TAG)Uninstalling httpie$(END) + - pip uninstall --yes httpie &2>/dev/null + + @echo "Verifying…" + cd .. && ! python -m httpie --version &2>/dev/null + + @echo "Done" + @echo + + +uninstall-all: uninstall-httpie + + @echo $(TAG)Uninstalling httpie requirements$(END) + - pip uninstall --yes pygments requests + + @echo $(TAG)Uninstalling development requirements$(END) + - pip uninstall --yes -r $(REQUIREMENTS) diff --git a/README.rst b/README.rst index 2c68568e..9e271d83 100644 --- a/README.rst +++ b/README.rst @@ -2,9 +2,9 @@ HTTPie: a CLI, cURL-like tool for humans **************************************** -HTTPie (pronounced *aych-tee-tee-pie*) is a **command line HTTP client**. Its -goal is to make CLI interaction with web services as **human-friendly** as -possible. It provides a simple ``http`` command that allows for sending +HTTPie (pronounced *aitch-tee-tee-pie*) is a **command line HTTP client**. +Its goal is to make CLI interaction with web services as **human-friendly** +as possible. It provides a simple ``http`` command that allows for sending arbitrary HTTP requests using a simple and natural syntax, and displays colorized output. HTTPie can be used for **testing, debugging**, and generally **interacting** with HTTP servers. @@ -588,6 +588,7 @@ Auth Plugins ------------ * `httpie-oauth `_: OAuth +* `httpie-hmac-auth `_: HMAC * `httpie-ntlm `_: NTLM (NT LAN Manager) * `httpie-negotiate `_: SPNEGO (GSS Negotiate) * `requests-hawk `_: Hawk diff --git a/appveyor.yml b/appveyor.yml index 1e73b258..f7067b89 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,8 +8,9 @@ init: - "ECHO %PYTHON%" - ps: "ls C:/Python*" install: - - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:/get-pip.py') - - "%PYTHON%/python.exe C:/get-pip.py" +# - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') +# - "%PYTHON%/python.exe C:/get-pip.py" + - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: - "%PYTHON%/Scripts/pip.exe --version" diff --git a/httpie/cli.py b/httpie/cli.py index 24e8d77a..0b9fb419 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -4,7 +4,7 @@ NOTE: the CLI interface may change before reaching v1.0. """ from textwrap import dedent, wrap -#noinspection PyCompatibility +# noinspection PyCompatibility from argparse import (RawDescriptionHelpFormatter, FileType, OPTIONAL, ZERO_OR_MORE, SUPPRESS) diff --git a/httpie/client.py b/httpie/client.py index d55ce62c..1115f4dd 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -15,9 +15,10 @@ try: # https://urllib3.readthedocs.org/en/latest/security.html urllib3.disable_warnings() except AttributeError: - # In some rare cases, the user may have an old version of the requests or urllib3, - # and there is no method called "disable_warnings." In these cases, we don't need to call - # the method. They may get some noisy output but execution shouldn't die. Move on + # In some rare cases, the user may have an old version of the requests + # or urllib3, and there is no method called "disable_warnings." In these + # cases, we don't need to call the method. + # They may get some noisy output but execution shouldn't die. Move on. pass diff --git a/httpie/config.py b/httpie/config.py index 9f28da17..64f72b2b 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -6,11 +6,11 @@ from httpie import __version__ from httpie.compat import is_windows -DEFAULT_CONFIG_DIR = os.environ.get( +DEFAULT_CONFIG_DIR = str(os.environ.get( 'HTTPIE_CONFIG_DIR', os.path.expanduser('~/.httpie') if not is_windows else os.path.expandvars(r'%APPDATA%\\httpie') -) +)) class BaseConfigDict(dict): diff --git a/httpie/input.py b/httpie/input.py index da3cc525..07698701 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -303,8 +303,8 @@ class Parser(ArgumentParser): # Infer the method has_data = ( (not self.args.ignore_stdin and not self.env.stdin_isatty) - or any(item.sep in SEP_GROUP_DATA_ITEMS - for item in self.args.items) + or any(item.sep in SEP_GROUP_DATA_ITEMS + for item in self.args.items) ) self.args.method = HTTP_POST if has_data else HTTP_GET @@ -378,7 +378,8 @@ class Parser(ArgumentParser): if self.args.prettify == PRETTY_STDOUT_TTY_ONLY: self.args.prettify = PRETTY_MAP[ 'all' if self.env.stdout_isatty else 'none'] - elif self.args.prettify and self.env.is_windows: + elif (self.args.prettify and self.env.is_windows and + self.args.output_file): self.error('Only terminal output can be colorized on Windows.') else: # noinspection PyTypeChecker @@ -521,7 +522,7 @@ class AuthCredentials(KeyValue): def _getpass(self, prompt): # To allow mocking. - return getpass.getpass(prompt) + return getpass.getpass(str(prompt)) def has_password(self): return self.value is not None @@ -572,7 +573,7 @@ class RequestItemsDict(OrderedDict): else: super(RequestItemsDict, self).__init__(*args, **kwargs) - #noinspection PyMethodOverriding + # noinspection PyMethodOverriding def __setitem__(self, key, value): """ If `key` is assigned more than once, `self[key]` holds a `list` of all the values. diff --git a/httpie/utils.py b/httpie/utils.py index ad2119aa..821fac9f 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -54,4 +54,3 @@ def humanize_bytes(n, precision=2): # noinspection PyUnboundLocalVariable return '%.*f %s' % (precision, n / factor, suffix) - diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..9735e581 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +addopts = --tb=native +norecursedirs = tests/fixtures diff --git a/setup.py b/setup.py index cab89c7c..9af19080 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,6 @@ class PyTest(TestCommand): # and runs the tests with no fancy stuff like parallel execution. def finalize_options(self): TestCommand.finalize_options(self) - self.test_suite = True self.test_args = [ '--doctest-modules', '--verbose', './httpie', './tests' @@ -40,12 +39,12 @@ install_requires = [ 'Pygments>=1.5' ] -### Conditional dependencies: +# Conditional dependencies: # sdist -if not 'bdist_wheel' in sys.argv: +if 'bdist_wheel' not in sys.argv: try: - #noinspection PyUnresolvedReferences + # noinspection PyUnresolvedReferences import argparse except ImportError: install_requires.append('argparse>=1.2.1') diff --git a/tests/fixtures.py b/tests/fixtures.py index c7b769e6..05737c71 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -38,4 +38,3 @@ with open(BIN_FILE_PATH, 'rb') as f: BIN_FILE_CONTENT = f.read() UNICODE = FILE_CONTENT - diff --git a/tests/test_auth.py b/tests/test_auth.py index 926a7900..a33211c2 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -60,4 +60,3 @@ class TestAuth: assert args.auth assert args.auth.key == 'username' assert args.auth.value == '' - diff --git a/tests/test_docs.py b/tests/test_docs.py index ed2ad1e9..a02f6510 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -9,7 +9,7 @@ from utils import TESTS_ROOT def has_docutils(): try: - #noinspection PyUnresolvedReferences + # noinspection PyUnresolvedReferences import docutils return True except ImportError: @@ -32,8 +32,8 @@ assert filenames def test_rst_file_syntax(filename): p = subprocess.Popen( ['rst2pseudoxml.py', '--report=1', '--exit-status=1', filename], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE + stderr=subprocess.PIPE, + stdout=subprocess.PIPE ) err = p.communicate()[1] assert p.returncode == 0, err diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 6a0d4b60..966d87b4 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -64,17 +64,20 @@ class TestSessionFlow(SessionTestBase): def test_session_update(self, httpbin): self.start_session(httpbin) # Get a response to a request from the original session. - r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r2 # Make a request modifying the session data. r3 = http('--follow', '--session=test', '--auth=username:password2', - 'GET', httpbin.url + '/cookies/set?hello=world2', 'Hello:World2', + 'GET', httpbin.url + '/cookies/set?hello=world2', + 'Hello:World2', env=self.env()) assert HTTP_OK in r3 # Get a response to a request from the updated session. - r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r4 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r4 assert r4.json['headers']['Hello'] == 'World2' assert r4.json['headers']['Cookie'] == 'hello=world2' @@ -84,7 +87,8 @@ class TestSessionFlow(SessionTestBase): def test_session_read_only(self, httpbin): self.start_session(httpbin) # Get a response from the original session. - r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r2 # Make a request modifying the session data but @@ -96,7 +100,8 @@ class TestSessionFlow(SessionTestBase): assert HTTP_OK in r3 # Get a response from the updated session. - r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r4 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r4 # Origin can differ on Travis. @@ -117,8 +122,8 @@ class TestSession(SessionTestBase): 'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT', env=self.env()) assert HTTP_OK in r1 - - r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r2 assert no_content_type(r2.json['headers']) assert 'If-Unmodified-Since' not in r2.json['headers'] diff --git a/tests/test_uploads.py b/tests/test_uploads.py index e97bdafb..0bf8457e 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -30,7 +30,7 @@ class TestMultipartFormDataFileUpload: 'test-file@%s' % FILE_PATH_ARG) assert HTTP_OK in r assert r.count('Content-Disposition: form-data; name="test-file";' - ' filename="%s"' % os.path.basename(FILE_PATH)) == 2 + ' filename="%s"' % os.path.basename(FILE_PATH)) == 2 # Should be 4, but is 3 because httpbin # doesn't seem to support filed field lists assert r.count(FILE_CONTENT) in [3, 4] diff --git a/tests/utils.py b/tests/utils.py index aad27395..5efdd011 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -53,7 +53,7 @@ class TestEnvironment(Environment): stdout_isatty = True is_windows = False - _shutil = shutil # needed by __del__ (would get gc'd) + _shutil_rmtree = shutil.rmtree # needed by __del__ (would get gc'd) def __init__(self, **kwargs): @@ -72,7 +72,7 @@ class TestEnvironment(Environment): def __del__(self): if self.delete_config_dir: - self._shutil.rmtree(self.config_dir) + self._shutil_rmtree(self.config_dir) def http(*args, **kwargs): diff --git a/tox.ini b/tox.ini index 600ba3f1..f746660f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,21 +1,22 @@ # Tox (http://tox.testrun.org/) is a tool for running tests -# in multiple virtualenvs. -# Run: -# $ pip install -r requirements-dev.txt -# $ tox +# in multiple virtualenvs. See ./CONTRIBUTING.rst [tox] -envlist = py26, py27, py34, pypy +envlist = py26, py27, py35, pypy [testenv] deps = + mock pytest pytest-httpbin>=0.0.6 -commands = - py.test --verbose --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} -[pytest] -addopts = --tb=native +commands = + # NOTE: the order of the directories in posargs seems to matter. + # When changed, then many ImportMismatchError exceptions occurrs. + py.test \ + --verbose \ + --doctest-modules \ + {posargs:./httpie ./tests}