Compare commits

...

36 Commits
0.9.4 ... 0.9.6

Author SHA1 Message Date
8e96238323 v0.9.6 2016-08-13 23:01:05 +02:00
8a9206eceb Fixed Makefile 2016-08-13 22:57:44 +02:00
8ac3c5961c Upgrade Pygments version 2016-08-13 22:57:33 +02:00
487c7a9221 v0.9.5 2016-08-13 22:51:42 +02:00
6d65668355 Strip request header values 2016-08-13 22:40:01 +02:00
3e5115e4a2 Merge pull request #501 from ii-v/master
Fixed spelling mistake in the AUTHORS.rst file
2016-08-11 08:37:41 +02:00
2b8b572f22 Merge pull request #1 from ii-v/ii-v-patch-1
Fixed spelling mistake `GitHib` to `GitHub`
2016-08-11 01:44:04 +02:00
af737fd338 Fixed spelling mistage GitHib to GitHub 2016-08-11 01:43:15 +02:00
ee375b6942 Merge pull request #493 from medecau/codestyle_environment
Codestyle environment
2016-07-29 23:17:00 +02:00
becb63de9a useful info 2016-07-26 21:59:34 +01:00
86c8abc485 force os to be linux (+1 squashed commit)
Squashed commits:
[444c56d] no vars for you (+1 squashed commit)
Squashed commits:
[c7d1bf9] added pycodestyle environment to travis config
2016-07-26 21:43:13 +01:00
8f6bee9196 codestyle fixes 2016-07-19 17:23:40 +01:00
9c2c058ae5 separate environment to test codestyle as proposed by @sigmavirus24 2016-07-19 17:23:18 +01:00
6238b59e72 Fix formatting 2016-07-08 15:05:43 +02:00
702c21aa91 Added related projects 2016-07-08 15:03:48 +02:00
aab5cd9da0 PEP8. clean-up 2016-07-04 20:30:55 +02:00
8c0f0b578c Clean-up 2016-07-02 18:44:02 +02:00
bb4881a873 Fixed README 2016-07-02 18:30:04 +02:00
3a1726b4ed Fixed README 2016-07-02 15:04:19 +02:00
e1fa57d228 Added -I as a shortcut for --ignore-stdin 2016-07-02 15:01:46 +02:00
bfc64bce21 Upgrade requests to 2.10.0 to enable optional SOCKS support
Closes #86
2016-07-02 14:58:34 +02:00
595dc51b2d Fish shell completion 2016-07-02 14:33:04 +02:00
83fa772247 Merge pull request #459 from dickeyxxx/fish-completion
added completions for fish shell
2016-07-02 14:31:06 +02:00
49a0fb6e0f More liberal default JSON Accept header
Closes #470
2016-07-02 14:18:36 +02:00
41e822ca2f Clean-up 2016-07-02 12:51:35 +02:00
1124d68946 Added --default-scheme <URL_SCHEME>
Closes #289
2016-07-02 12:47:02 +02:00
c3735d0422 Merge pull request #401 from lgarron/default-scheme
Add a --default-scheme argument.
2016-07-02 12:32:07 +02:00
364b91cbc4 Skip pypy3 tests on TravisCI 2016-07-02 12:03:52 +02:00
c8e06b55e1 Fix tests 2016-07-02 12:03:19 +02:00
5acbc904b7 Added the ability to unset headers
Closes #476
2016-07-02 11:50:30 +02:00
0c7c248dce Fix CHANGELOG 2016-07-02 11:17:38 +02:00
caf60cbc65 Typos 2016-07-02 11:11:06 +02:00
2b0e642842 Document preference for Python 3
Also mention that the Homebrew formula depends on Python 3 starting with HTTPie 0.9.4.
2016-07-02 11:07:46 +02:00
e25948f6a0 1.0.0-dev 2016-07-01 19:17:31 +02:00
ec245a1e80 added completions for fish shell 2016-04-06 11:28:03 -07:00
6259b5dd3b Add a --default-scheme argument. 2015-10-28 15:06:04 -07:00
21 changed files with 412 additions and 109 deletions

View File

@ -15,7 +15,8 @@ python:
- pypy
- 3.4
- 3.5
- pypy3
# Currently fails because of a Flask issue
# - pypy3
matrix:
@ -44,6 +45,11 @@ matrix:
- TOXENV=py35
- BREW_INSTALL=python3
# Python Codestyle
- os: linux
python: 3.5
env: CODESTYLE=true
install:
- |
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
@ -53,11 +59,20 @@ install:
fi
sudo pip install tox
fi
if [[ $CODESTYLE ]]; then
pip install pycodestyle
fi
script:
- |
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
make
if [[ $CODESTYLE ]]; then
# 241 - multiple spaces after ,
# 501 - line too long
pycodestyle --ignore=E241,E501
else
make
fi
else
PATH="/usr/local/bin:$PATH" tox -e "$TOXENV"
fi

View File

@ -8,7 +8,7 @@ HTTPie authors
Patches and ideas
-----------------
`Complete list of contributors on GitHib <https://github.com/jkbrzt/httpie/graphs/contributors>`_
`Complete list of contributors on GitHub <https://github.com/jkbrzt/httpie/graphs/contributors>`_
* `Cláudia T. Delgado <https://github.com/claudiatd>`_ (logo)
* `Hank Gay <https://github.com/gthank>`_

View File

@ -10,6 +10,27 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
-------------------------
`0.9.6`_ (2016-08-13)
---------------------
* Added Python 3 as a dependency for Homebrew installations
to ensure some of the newer HTTP features work out of the box
for macOS users (starting with HTTPie 0.9.4.).
* Added the ability to unset a request header with ``Header:``, and send an
empty value with ``Header;``.
* Added ``--default-scheme <URL_SCHEME>`` to enable things like
``$ alias https='http --default-scheme=https``.
* Added ``-I`` as a shortcut for ``--ignore-stdin``.
* Added fish shell completion (located in ``extras/httpie-completion.fish``
in the Github repo).
* Updated ``requests`` to 2.10.0 so that SOCKS support can be added via
``pip install requests[socks]``.
* Changed the default JSON ``Accept`` header from ``application/json``
to ``application/json, */*``.
* Changed the pre-processing of request HTTP headers so that any leading
and trailing whitespace is removed.
`0.9.4`_ (2016-07-01)
---------------------
@ -289,4 +310,5 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
.. _0.9.2: https://github.com/jkbrzt/httpie/compare/0.9.1...0.9.2
.. _0.9.3: https://github.com/jkbrzt/httpie/compare/0.9.2...0.9.3
.. _0.9.4: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.4
.. _0.9.6: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.6
.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.4...master

View File

@ -57,10 +57,12 @@ test-bdist-wheel: clean uninstall-httpie
test-all: uninstall-all clean init test test-tox test-dist
publish: test-all
publish: test-all publish-no-test
publish-no-test:
@echo $(TAG)Testing wheel build an installation$(END)
@echo "$(VERSION)"
@echo "$(VERSION)" | grep -q "dev" && echo "!!!Not publishing dev version!!!" && exit 1
@echo "$(VERSION)" | grep -q "dev" && echo '!!!Not publishing dev version!!!' && exit 1 || echo ok
python setup.py register
python setup.py sdist upload
python setup.py bdist_wheel upload
@ -92,3 +94,7 @@ uninstall-all: uninstall-httpie
@echo $(TAG)Uninstalling development requirements$(END)
- pip uninstall --yes -r $(REQUIREMENTS)
homebrew-formula-vars:
extras/get-homebrew-formula-vars.py

View File

@ -35,7 +35,7 @@ HTTPie is written in Python, and under the hood it uses the excellent
=============
Main Features
Main features
=============
* Expressive and intuitive syntax
@ -117,6 +117,17 @@ The **latest development version** can be installed directly from GitHub:
$ pip install --upgrade https://github.com/jkbrzt/httpie/archive/master.tar.gz
--------------
Python version
--------------
Although Python 2.6 and 2.7 are supported as well, it is recommended to install
HTTPie against the latest Python 3.x whenever possible. That will ensure that
some of the newer HTTP features, such as `SNI (Server Name Indication)`_,
work out of the box.
Python 3 is the default for Homebrew installations starting with version 0.9.4.
To see which version HTTPie uses, run ``http --debug``.
=====
Usage
@ -172,7 +183,7 @@ with `authentication`_:
.. code-block:: bash
$ http -a USERNAME POST https://api.github.com/repos/jkbrzt/httpie/issues/83/comments body='HTTPie is awesome!'
$ http -a USERNAME POST https://api.github.com/repos/jkbrzt/httpie/issues/83/comments body='HTTPie is awesome! :heart:'
Upload a file using `redirected input`_:
@ -220,7 +231,7 @@ advanced usage, and also features additional examples.*
===========
HTTP Method
HTTP method
===========
The name of the HTTP method comes right before the URL argument:
@ -302,9 +313,16 @@ this command:
GET /?search=HTTPie+logo&tbm=isch HTTP/1.1
You can use the ``--default-scheme <URL_SCHEME>`` option to create
shortcuts for other protocols than HTTP:
.. code-block:: bash
$ alias https='http --default-scheme=https'
=============
Request Items
Request items
=============
There are a few different *request item* types that provide a
@ -385,13 +403,13 @@ both of which can be overwritten:
================ =======================================
``Content-Type`` ``application/json``
``Accept`` ``application/json``
``Accept`` ``application/json, */*``
================ =======================================
You can use ``--json, -j`` to explicitly set ``Accept``
to ``application/json`` regardless of whether you are sending data
(it's a shortcut for setting the header via the usual header notation
``http url Accept:application/json``). Additionally,
``http url Accept:application/json, */*``). Additionally,
HTTPie will try to detect JSON responses even when the
``Content-Type`` is incorrectly ``text/plain`` or unknown.
@ -404,7 +422,7 @@ Simple example:
.. code-block:: http
PUT / HTTP/1.1
Accept: application/json
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Content-Type: application/json
Host: example.org
@ -431,7 +449,7 @@ fields using ``=@`` and ``:=@``:
.. code-block:: http
PUT /person/1 HTTP/1.1
Accept: application/json
Accept: application/json, */*
Content-Type: application/json
Host: api.example.com
@ -471,7 +489,7 @@ via the `config`_ file.
-------------
Regular Forms
Regular forms
-------------
.. code-block:: bash
@ -489,7 +507,7 @@ Regular Forms
-----------------
File Upload Forms
File upload forms
-----------------
If one or more file fields is present, the serialization and content type is
@ -515,7 +533,7 @@ Note that ``@`` is used to simulate a file upload form field, whereas
============
HTTP Headers
HTTP headers
============
To set custom headers you can use the ``Header:Value`` notation:
@ -549,7 +567,23 @@ There are a couple of default headers that HTTPie sets:
Host: <taken-from-URL>
Any of the default headers can be overwritten.
Any of the default headers can be overwritten and some of them unset.
To unset a header that has already been specified (such a one of the default
headers), use ``Header:``:
.. code-block:: bash
$ http httpbin.org/headers Accept: User-Agent:
To send a header with an empty value, use ``Header;``:
.. code-block:: bash
$ http httpbin.org/headers 'Header;'
==============
@ -614,7 +648,7 @@ Authorization information from your ``~/.netrc`` file is honored as well:
------------
Auth Plugins
Auth plugins
------------
* `httpie-oauth <https://github.com/jkbrzt/httpie-oauth>`_: OAuth
@ -628,7 +662,7 @@ Auth Plugins
==============
HTTP Redirects
HTTP redirects
==============
By default, HTTP redirects are not followed and only the first
@ -679,6 +713,24 @@ In your ``~/.bash_profile``:
export NO_PROXY=localhost,example.com
-----
SOCKS
-----
To enable SOCKS proxy support please install ``requests[socks]`` using ``pip``:
.. code-block:: bash
$ pip install -U requests[socks]
Usage is the same as for other types of `proxies`_:
.. code-block:: bash
$ http --proxy=http:socks5://user:pass@host:port --proxy=https:socks5://user:pass@host:port example.org
=====
HTTPS
=====
@ -750,8 +802,8 @@ available set of protocols may vary depending on your OpenSSL installation.)
SNI (Server Name Indication)
----------------------------
If you use HTTPie with Python < 2.7.9
(can be verified with ``python --version``) and need to talk to servers that
If you use HTTPie with `Python version`_ lower than 2.7.9
(can be verified with ``http --debug``) and need to talk to servers that
use **SNI (Server Name Indication)** you need to install some additional
dependencies:
@ -768,7 +820,7 @@ You can use the following command to test SNI support:
==============
Output Options
Output options
==============
By default, HTTPie only outputs the final response and the whole response
@ -791,7 +843,7 @@ documentation examples:
$ http --verbose PUT httpbin.org/put hello=world
PUT /put HTTP/1.1
Accept: application/json
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Content-Type: application/json
Host: httpbin.org
@ -835,11 +887,11 @@ Print request and response headers:
---------------------------------------
Viewing Intermediary Requests/Responses
Viewing intermediary requests/responses
---------------------------------------
To see *all* the HTTP communication, i.e. the final request/resposne as
well as any possible intermediary requests/responses, use the **``--all``**
To see *all* the HTTP communication, i.e. the final request/response as
well as any possible intermediary requests/responses, use the ``--all``
option. The intermediary HTTP communication include followed redirects
(with ``--follow``), the first unauthorized request when HTTP digest
authentication is used (``--auth=digest``), etc.
@ -863,7 +915,7 @@ arguments as ``--print, -p`` but applies to the intermediary requests only.
-------------------------
Conditional Body Download
Conditional body download
-------------------------
As an optimization, the response body is downloaded from the server
@ -961,9 +1013,9 @@ To prevent HTTPie from reading ``stdin`` data you can use the
``--ignore-stdin`` option.
-------------------------
Body Data From a Filename
-------------------------
----------------------------
Request data from a filename
----------------------------
**An alternative to redirected** ``stdin`` is specifying a filename (as
``@/path/to/file``) whose content is used as if it came from ``stdin``.
@ -979,7 +1031,7 @@ verbatim contents of that XML file with ``Content-Type: application/xml``:
===============
Terminal Output
Terminal output
===============
HTTPie does several things by default in order to make its terminal output
@ -987,7 +1039,7 @@ easy to read.
---------------------
Colors and Formatting
Colors and formatting
---------------------
Syntax highlighting is applied to HTTP headers and bodies (where it makes
@ -1042,7 +1094,7 @@ You will nearly instantly see something like this:
=================
Redirected Output
Redirected output
=================
HTTPie uses **different defaults** for redirected output than for
@ -1093,7 +1145,7 @@ by adding the following to your ``~/.bash_profile``:
=============
Download Mode
Download mode
=============
HTTPie features a download mode in which it acts similarly to ``wget``.
@ -1150,7 +1202,7 @@ Other notes:
==================
Streamed Responses
Streamed responses
==================
Responses are downloaded and printed in chunks, which allows for streaming
@ -1197,7 +1249,7 @@ ones starting with ``Content-`` or ``If-``), authorization, and cookies
to the same host.
--------------
Named Sessions
Named sessions
--------------
Create a new session named ``user1`` for ``example.org``:
@ -1228,7 +1280,7 @@ Named sessions' data is stored in JSON files in the directory
(``%APPDATA%\httpie\sessions\<host>\<name>.json`` on Windows).
------------------
Anonymous Sessions
Anonymous sessions
------------------
Instead of a name, you can also directly specify a path to a session file. This
@ -1322,7 +1374,7 @@ Also, the ``--timeout`` option allows to overwrite the default 30s timeout:
================
Interface Design
Interface design
================
The syntax of the command arguments closely corresponds to the actual HTTP
@ -1396,28 +1448,39 @@ have contributed.
Logo
====
Please see `claudiatd/httpie-artwork`_
See `claudiatd/httpie-artwork`_
==========
Contribute
==========
Please see `CONTRIBUTING <https://github.com/jkbrzt/httpie/blob/master/CONTRIBUTING.rst>`_.
See `CONTRIBUTING <https://github.com/jkbrzt/httpie/blob/master/CONTRIBUTING.rst>`_.
==========
Change Log
Change log
==========
Please see `CHANGELOG <https://github.com/jkbrzt/httpie/blob/master/CHANGELOG.rst>`_.
See `CHANGELOG <https://github.com/jkbrzt/httpie/blob/master/CHANGELOG.rst>`_.
=======
Licence
=======
Please see `LICENSE <https://github.com/jkbrzt/httpie/blob/master/LICENSE>`_.
See `LICENSE <https://github.com/jkbrzt/httpie/blob/master/LICENSE>`_.
================
Related projects
================
* `jq <https://stedolan.github.io/jq/>`_ — a command-line JSON processor that
works great in conjunction with HTTPie
* `http-prompt <https://github.com/eliangcs/http-prompt>`_ — an interactive
shell for HTTPie featuring autocomplete and command syntax highlighting

View File

@ -0,0 +1,55 @@
#!/usr/bin/env python
"""
Generate URLs and file hashes to be included in the Homebrew formula
after a new release of HTTPie is published on PyPi.
https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb
"""
import hashlib
import requests
PACKAGES = [
'httpie',
'requests',
'pygments',
]
def get_info(package_name):
api_url = 'https://pypi.python.org/pypi/{}/json'.format(package_name)
resp = requests.get(api_url).json()
hasher = hashlib.sha256()
for release in resp['urls']:
download_url = release['url']
if download_url.endswith('.tar.gz'):
hasher.update(requests.get(download_url).content)
return {
'name': package_name,
'url': download_url,
'sha256': hasher.hexdigest(),
}
else:
raise RuntimeError(
'{}: download not found: {}'.format(package_name, resp))
packages = {
package_name: get_info(package_name) for package_name in PACKAGES
}
httpie_info = packages.pop('httpie')
print("""
url "{url}"
sha256 "{sha256}"
""".format(**httpie_info))
for package_info in packages.values():
print("""
resource "{name}" do
url "{url}"
sha256 "{sha256}"
end""".format(**package_info))

View File

@ -0,0 +1,60 @@
function __fish_httpie_auth_types
echo "basic"\t"Basic HTTP auth"
echo "digest"\t"Digest HTTP auth"
end
function __fish_httpie_styles
echo "autumn"
echo "borland"
echo "bw"
echo "colorful"
echo "default"
echo "emacs"
echo "friendly"
echo "fruity"
echo "igor"
echo "manni"
echo "monokai"
echo "murphy"
echo "native"
echo "paraiso-dark"
echo "paraiso-light"
echo "pastie"
echo "perldoc"
echo "rrt"
echo "solarized"
echo "tango"
echo "trac"
echo "vim"
echo "vs"
echo "xcode"
end
complete -x -c http -s s -l style -d 'Output coloring style (default is "monokai")' -A -a "autumn borland bw colorful default emacs friendly fruity igor manni monokai murphy native paraiso-dark paraiso-light pastie perldoc rrt solarized tango trac vim vs xcode"
complete -c http -s f -l form -d 'Data items from the command line are serialized as form fields'
complete -c http -s j -l json -d '(default) Data items from the command line are serialized as a JSON object'
complete -x -c http -l pretty -d 'Controls output processing' -a "all colors format none" -A
complete -x -c http -s s -l style -d 'Output coloring style (default is "monokai")' -A -a "autumn borland bw colorful default emacs friendly fruity igor manni monokai murphy native paraiso-dark paraiso-light pastie perldoc rrt solarized tango trac vim vs xcode"
complete -x -c http -s p -l print -d 'String specifying what the output should contain'
complete -c http -s v -l verbose -d 'Print the whole request as well as the response'
complete -c http -s h -l headers -d 'Print only the response headers'
complete -c http -s b -l body -d 'Print only the response body'
complete -c http -s S -l stream -d 'Always stream the output by line'
complete -c http -s o -l output -d 'Save output to FILE'
complete -c http -s d -l download -d 'Do not print the response body to stdout'
complete -c http -s c -l continue -d 'Resume an interrupted download'
complete -x -c http -l session -d 'Create, or reuse and update a session'
complete -x -c http -s a -l auth -d 'If only the username is provided (-a username), HTTPie will prompt for the password'
complete -x -c http -l auth-type -d 'The authentication mechanism to be used' -a '(__fish_httpie_auth_types)' -A
complete -x -c http -l proxy -d 'String mapping protocol to the URL of the proxy'
complete -c http -l follow -d 'Allow full redirects'
complete -x -c http -l verify -d 'SSL cert verification'
complete -c http -l cert -d 'SSL cert'
complete -c http -l cert-key -d 'Private SSL cert key'
complete -x -c http -l timeout -d 'Connection timeout in seconds'
complete -c http -l check-status -d 'Error with non-200 HTTP status code'
complete -c http -l ignore-stdin -d 'Do not attempt to read stdin'
complete -c http -l help -d 'Show help'
complete -c http -l version -d 'Show version'
complete -c http -l traceback -d 'Prints exception traceback should one occur'
complete -c http -l debug -d 'Show debugging information'

View File

@ -3,7 +3,7 @@ HTTPie - a CLI, cURL-like tool for humans.
"""
__author__ = 'Jakub Roztocil'
__version__ = '0.9.4'
__version__ = '0.9.6'
__licence__ = 'BSD'

View File

@ -89,6 +89,7 @@ positional.add_argument(
metavar='URL',
help="""
The scheme defaults to 'http://' if the URL does not include one.
(You can override this with: --default-scheme=https)
You can also use a shorthand for localhost
@ -212,7 +213,7 @@ output_processing.add_argument(
""".format(
default=DEFAULT_STYLE,
available='\n'.join(
'{0}{1}'.format(8*' ', line.strip())
'{0}{1}'.format(8 * ' ', line.strip())
for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60)
).rstrip(),
)
@ -576,7 +577,7 @@ ssl.add_argument(
troubleshooting = parser.add_argument_group(title='Troubleshooting')
troubleshooting.add_argument(
'--ignore-stdin',
'--ignore-stdin', '-I',
action='store_true',
default=False,
help="""
@ -611,6 +612,14 @@ troubleshooting.add_argument(
"""
)
troubleshooting.add_argument(
'--default-scheme',
default="http",
help="""
The default scheme to use if not specified in the URL.
"""
)
troubleshooting.add_argument(
'--debug',
action='store_true',

View File

@ -1,6 +1,5 @@
import json
import sys
from pprint import pformat
import requests
from requests.adapters import HTTPAdapter
@ -24,8 +23,9 @@ except AttributeError:
pass
FORM = 'application/x-www-form-urlencoded; charset=utf-8'
JSON = 'application/json'
FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8'
JSON_CONTENT_TYPE = 'application/json'
JSON_ACCEPT = '{0}, */*'.format(JSON_CONTENT_TYPE)
DEFAULT_UA = 'HTTPie/%s' % __version__
@ -85,13 +85,23 @@ def dump_request(kwargs):
% repr_dict_nice(kwargs))
def encode_headers(headers):
# This allows for unicode headers which is non-standard but practical.
# See: https://github.com/jkbrzt/httpie/issues/212
return dict(
(name, value.encode('utf8') if isinstance(value, str) else value)
for name, value in headers.items()
)
def finalize_headers(headers):
final_headers = {}
for name, value in headers.items():
if value is not None:
# >leading or trailing LWS MAY be removed without
# >changing the semantics of the field value"
# -https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
# Also, requests raises `InvalidHeader` for leading spaces.
value = value.strip()
if isinstance(value, str):
# See: https://github.com/jkbrzt/httpie/issues/212
value = value.encode('utf8')
final_headers[name] = value
return final_headers
def get_default_headers(args):
@ -100,16 +110,15 @@ def get_default_headers(args):
}
auto_json = args.data and not args.form
# FIXME: Accept is set to JSON with `http url @./file.txt`.
if args.json or auto_json:
default_headers['Accept'] = 'application/json'
default_headers['Accept'] = JSON_ACCEPT
if args.json or (auto_json and args.data):
default_headers['Content-Type'] = JSON
default_headers['Content-Type'] = JSON_CONTENT_TYPE
elif args.form and not args.files:
# If sending files, `requests` will set
# the `Content-Type` for us.
default_headers['Content-Type'] = FORM
default_headers['Content-Type'] = FORM_CONTENT_TYPE
return default_headers
@ -134,7 +143,7 @@ def get_requests_kwargs(args, base_headers=None):
if base_headers:
headers.update(base_headers)
headers.update(args.headers)
headers = encode_headers(headers)
headers = finalize_headers(headers)
credentials = None
if args.auth:

View File

@ -14,10 +14,14 @@ is_windows = 'win32' in str(sys.platform).lower()
if is_py2:
# noinspection PyShadowingBuiltins
bytes = str
# noinspection PyUnresolvedReferences,PyShadowingBuiltins
str = unicode
elif is_py3:
# noinspection PyShadowingBuiltins
str = str
# noinspection PyShadowingBuiltins
bytes = bytes
@ -32,7 +36,7 @@ try: # pragma: no cover
# noinspection PyCompatibility
from urllib.request import urlopen
except ImportError: # pragma: no cover
# noinspection PyCompatibility
# noinspection PyCompatibility,PyUnresolvedReferences
from urllib2 import urlopen
try: # pragma: no cover
@ -40,10 +44,10 @@ try: # pragma: no cover
except ImportError: # pragma: no cover
# Python 2.6 OrderedDict class, needed for headers, parameters, etc .###
# <https://pypi.python.org/pypi/ordereddict/1.1>
# noinspection PyCompatibility
# noinspection PyCompatibility,PyUnresolvedReferences
from UserDict import DictMixin
# noinspection PyShadowingBuiltins
# noinspection PyShadowingBuiltins,PyCompatibility
class OrderedDict(dict, DictMixin):
# Copyright (c) 2009 Raymond Hettinger
#
@ -115,6 +119,7 @@ except ImportError: # pragma: no cover
if not self:
raise KeyError('dictionary is empty')
if last:
# noinspection PyUnresolvedReferences
key = reversed(self).next()
else:
key = iter(self).next()

View File

@ -243,7 +243,7 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None):
except requests.TooManyRedirects:
exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS
log_error('Too many redirects (--max-redirects=%s).',
parsed_args.max_redirects)
parsed_args.max_redirects)
except Exception as e:
# TODO: Further distinction between expected and unexpected errors.
msg = str(e)

View File

@ -78,15 +78,15 @@ def parse_content_range(content_range, resumed_from):
# last-byte-pos value, is invalid. The recipient of an invalid
# byte-content-range- spec MUST ignore it and any content
# transferred along with it."
if (first_byte_pos >= last_byte_pos
or (instance_length is not None
and instance_length <= last_byte_pos)):
if (first_byte_pos >= last_byte_pos or
(instance_length is not None and
instance_length <= last_byte_pos)):
raise ContentRangeError(
'Invalid Content-Range returned: %r' % content_range)
if (first_byte_pos != resumed_from
or (instance_length is not None
and last_byte_pos + 1 != instance_length)):
if (first_byte_pos != resumed_from or
(instance_length is not None and
last_byte_pos + 1 != instance_length)):
# Not what we asked for.
raise ContentRangeError(
'Unexpected Content-Range returned (%r)'
@ -308,9 +308,9 @@ class Downloader(object):
@property
def interrupted(self):
return (
self.finished
and self.status.total_size
and self.status.total_size != self.status.downloaded
self.finished and
self.status.total_size and
self.status.total_size != self.status.downloaded
)
def chunk_downloaded(self, chunk):
@ -399,8 +399,8 @@ class ProgressReporterThread(threading.Thread):
if now - self._prev_time >= self._update_interval:
downloaded = self.status.downloaded
try:
speed = ((downloaded - self._prev_bytes)
/ (now - self._prev_time))
speed = ((downloaded - self._prev_bytes) /
(now - self._prev_time))
except ZeroDivisionError:
speed = 0
@ -434,11 +434,11 @@ class ProgressReporterThread(threading.Thread):
self._prev_bytes = downloaded
self.output.write(
CLEAR_LINE
+ ' '
+ SPINNER[self._spinner_pos]
+ ' '
+ self._status_line
CLEAR_LINE +
' ' +
SPINNER[self._spinner_pos] +
' ' +
self._status_line
)
self.output.flush()
@ -447,8 +447,8 @@ class ProgressReporterThread(threading.Thread):
else 0)
def sum_up(self):
actually_downloaded = (self.status.downloaded
- self.status.resumed_from)
actually_downloaded = (
self.status.downloaded - self.status.resumed_from)
time_taken = self.status.time_finished - self.status.time_started
self.output.write(CLEAR_LINE)
@ -463,8 +463,8 @@ class ProgressReporterThread(threading.Thread):
self.output.write(SUMMARY.format(
downloaded=humanize_bytes(actually_downloaded),
total=(self.status.total_size
and humanize_bytes(self.status.total_size)),
total=(self.status.total_size and
humanize_bytes(self.status.total_size)),
speed=humanize_bytes(speed),
time=time_taken,
))

View File

@ -28,12 +28,11 @@ URL_SCHEME_RE = re.compile(r'^[a-z][a-z0-9.+-]*://', re.IGNORECASE)
HTTP_POST = 'POST'
HTTP_GET = 'GET'
HTTP = 'http://'
HTTPS = 'https://'
# Various separators used in args
SEP_HEADERS = ':'
SEP_HEADERS_EMPTY = ';'
SEP_CREDENTIALS = ':'
SEP_PROXY = ':'
SEP_DATA = '='
@ -67,6 +66,7 @@ SEP_GROUP_RAW_JSON_ITEMS = frozenset([
# Separators allowed in ITEM arguments
SEP_GROUP_ALL_ITEMS = frozenset([
SEP_HEADERS,
SEP_HEADERS_EMPTY,
SEP_QUERY,
SEP_DATA,
SEP_DATA_RAW_JSON,
@ -151,7 +151,7 @@ class HTTPieArgumentParser(ArgumentParser):
if not self.args.ignore_stdin and not env.stdin_isatty:
self._body_from_file(self.env.stdin)
if not URL_SCHEME_RE.match(self.args.url):
scheme = HTTP
scheme = self.args.default_scheme + "://"
# See if we're using curl style shorthand for localhost (:3000/foo)
shorthand = re.match(r'^:(?!:)(\d*)(/?.*)$', self.args.url)
@ -309,9 +309,10 @@ class HTTPieArgumentParser(ArgumentParser):
self.args.url = self.args.method
# 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)
(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)
)
self.args.method = HTTP_POST if has_data else HTTP_GET
@ -439,8 +440,8 @@ class SessionNameValidator(object):
def __call__(self, value):
# Session name can be a path or just a name.
if (os.path.sep not in value
and not VALID_SESSION_NAME_PATTERN.search(value)):
if (os.path.sep not in value and
not VALID_SESSION_NAME_PATTERN.search(value)):
raise ArgumentError(None, self.error_message)
return value
@ -655,11 +656,20 @@ def parse_items(items,
data = []
files = []
params = []
for item in items:
value = item.value
if item.sep == SEP_HEADERS:
if value == '':
# No value => unset the header
value = None
target = headers
elif item.sep == SEP_HEADERS_EMPTY:
if item.value:
raise ParseError(
'Invalid item "%s" '
'(to specify an empty header use `Header;`)'
% item.orig
)
target = headers
elif item.sep == SEP_QUERY:
target = params

View File

@ -5,6 +5,7 @@ import requests.auth
from httpie.plugins.base import AuthPlugin
# noinspection PyAbstractClass
class BuiltinAuthPlugin(AuthPlugin):
package_name = '(builtin)'

View File

@ -35,10 +35,11 @@ tests_require = [
install_requires = [
'requests>=2.3.0',
'Pygments>=1.5'
'requests>=2.11.0',
'Pygments>=2.1.3'
]
# Conditional dependencies:
# sdist

View File

@ -68,10 +68,11 @@ class TestItemParsing:
def test_valid_items(self):
items = input.parse_items([
self.key_value('string=value'),
self.key_value('header:value'),
self.key_value('Header:value'),
self.key_value('Unset-Header:'),
self.key_value('Empty-Header;'),
self.key_value('list:=["a", 1, {}, false]'),
self.key_value('obj:={"a": "b"}'),
self.key_value('eh:'),
self.key_value('ed='),
self.key_value('bool:=true'),
self.key_value('file@' + FILE_PATH_ARG),
@ -83,7 +84,11 @@ class TestItemParsing:
# Parsed headers
# `requests.structures.CaseInsensitiveDict` => `dict`
headers = dict(items.headers._store.values())
assert headers == {'header': 'value', 'eh': ''}
assert headers == {
'Header': 'value',
'Unset-Header': None,
'Empty-Header': ''
}
# Parsed data
raw_json_embed = items.data.pop('raw-json-embed')
@ -103,8 +108,8 @@ class TestItemParsing:
# Parsed file fields
assert 'file' in items.files
assert (items.files['file'][1].read().strip().decode('utf8')
== FILE_CONTENT)
assert (items.files['file'][1].read().strip().
decode('utf8') == FILE_CONTENT)
def test_multiple_file_fields_with_same_field_name(self):
items = input.parse_items([
@ -325,8 +330,18 @@ class TestIgnoreStdin:
class TestSchemes:
def test_custom_scheme(self):
def test_invalid_custom_scheme(self):
# InvalidSchema is expected because HTTPie
# shouldn't touch a formally valid scheme.
with pytest.raises(InvalidSchema):
http('foo+bar-BAZ.123://bah')
def test_invalid_scheme_via_via_default_scheme(self):
# InvalidSchema is expected because HTTPie
# shouldn't touch a formally valid scheme.
with pytest.raises(InvalidSchema):
http('bah', '--default=scheme=foo+bar-BAZ.123')
def test_default_scheme(self, httpbin_secure):
url = '{0}:{1}'.format(httpbin_secure.host, httpbin_secure.port)
assert HTTP_OK in http(url, '--default-scheme=https')

View File

@ -2,6 +2,7 @@
Tests for the provided defaults regarding HTTP method, and --json vs. --form.
"""
from httpie.client import JSON_ACCEPT
from utils import TestEnvironment, http, HTTP_OK
from fixtures import FILE_PATH
@ -58,20 +59,20 @@ class TestAutoContentTypeAndAcceptHeaders:
def test_POST_with_data_auto_JSON_headers(self, httpbin):
r = http('POST', httpbin.url + '/post', 'a=b')
assert HTTP_OK in r
assert '"Accept": "application/json"' in r
assert '"Content-Type": "application/json' in r
assert r.json['headers']['Accept'] == JSON_ACCEPT
assert r.json['headers']['Content-Type'] == 'application/json'
def test_GET_with_data_auto_JSON_headers(self, httpbin):
# JSON headers should automatically be set also for GET with data.
r = http('POST', httpbin.url + '/post', 'a=b')
assert HTTP_OK in r
assert '"Accept": "application/json"' in r, r
assert '"Content-Type": "application/json' in r
assert r.json['headers']['Accept'] == JSON_ACCEPT
assert r.json['headers']['Content-Type'] == 'application/json'
def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin):
r = http('--json', 'POST', httpbin.url + '/post')
assert HTTP_OK in r
assert r.json['headers']['Accept'] == 'application/json'
assert r.json['headers']['Accept'] == JSON_ACCEPT
# Make sure Content-Type gets set even with no data.
# https://github.com/jkbrzt/httpie/issues/137
assert 'application/json' in r.json['headers']['Content-Type']

View File

@ -1,5 +1,7 @@
"""High-level tests."""
import pytest
from httpie.input import ParseError
from utils import TestEnvironment, http, HTTP_OK
from fixtures import FILE_PATH, FILE_CONTENT
@ -75,6 +77,27 @@ def test_headers(httpbin_both):
assert '"Foo": "bar"' in r
def test_headers_unset(httpbin_both):
r = http('GET', httpbin_both + '/headers')
assert 'Accept' in r.json['headers'] # default Accept present
r = http('GET', httpbin_both + '/headers', 'Accept:')
assert 'Accept' not in r.json['headers'] # default Accept unset
def test_headers_empty_value(httpbin_both):
r = http('GET', httpbin_both + '/headers')
assert r.json['headers']['Accept'] # default Accept has value
r = http('GET', httpbin_both + '/headers', 'Accept;')
assert r.json['headers']['Accept'] == '' # Accept has no value
def test_headers_empty_value_with_value_gives_error(httpbin):
with pytest.raises(ParseError):
http('GET', httpbin + '/headers', 'Accept;SYNTAX_ERROR')
@pytest.mark.skipif(
is_py26,
reason='the `object_pairs_hook` arg for `json.loads()` is Py>2.6 only'

10
tox.ini
View File

@ -3,7 +3,7 @@
[tox]
envlist = py26, py27, py35, pypy
envlist = py26, py27, py35, pypy, codestyle
[testenv]
@ -20,3 +20,11 @@ commands =
--verbose \
--doctest-modules \
{posargs:./httpie ./tests}
[testenv:codestyle]
deps = pycodestyle
commands =
pycodestyle \
--ignore=E241,E501
# 241 - multiple spaces after ,
# 501 - line too long