mirror of
https://github.com/httpie/cli.git
synced 2025-08-12 16:37:49 +02:00
Compare commits
96 Commits
Author | SHA1 | Date | |
---|---|---|---|
2e96d7ffbb | |||
b5625e3d75 | |||
932d3224f4 | |||
b596fedf13 | |||
96444f3345 | |||
89b66f1608 | |||
a7d570916d | |||
ab5a50cee8 | |||
91961c6b51 | |||
256ea7d49d | |||
2cd6ea3050 | |||
37dddf5bf7 | |||
e508c631f2 | |||
55530c8c6d | |||
eb929cbc04 | |||
2490bb25ca | |||
2038fa02e3 | |||
59d51ad513 | |||
61568f1def | |||
f93f4fa7c7 | |||
bf73b5701e | |||
7917f1b40c | |||
a50660cc70 | |||
749b1e2aca | |||
137889a267 | |||
c9c6f0fae5 | |||
6fd1ea0e5a | |||
8f7676a2a9 | |||
87e661c5f1 | |||
8ca333dda0 | |||
0f4dce98c7 | |||
05547224ce | |||
6301fee3d2 | |||
a803e845a5 | |||
11be041e06 | |||
7f5fd130c5 | |||
ec899d70b7 | |||
4d3b4fa0be | |||
27c557e983 | |||
7f24f7d34c | |||
4b61108005 | |||
8b189725fd | |||
1719ebded6 | |||
c5d6a4ad8e | |||
91e1fe2d0f | |||
ca7f41de53 | |||
46e24dd6b5 | |||
803127e8c9 | |||
4c138959ea | |||
91a28973bd | |||
02b28093a8 | |||
d64e7d8a6a | |||
8841b8bf46 | |||
6472ca55e1 | |||
37c3307018 | |||
0aab796960 | |||
95c33e31a2 | |||
9af833da30 | |||
dfe6245cd6 | |||
555761f3cb | |||
643735ef23 | |||
7a45f14542 | |||
e993f83355 | |||
d726a4cd92 | |||
8d3f09497b | |||
31c78c2885 | |||
9776a6dea0 | |||
f1d4861fae | |||
d99e1ff492 | |||
a196d1d451 | |||
02209c2db1 | |||
9886f01f91 | |||
a4f796fe69 | |||
c948f98b05 | |||
b0fde07cfd | |||
f74670fac1 | |||
7321b9fa4e | |||
cf8d5eb3e8 | |||
64af72eb88 | |||
de38f86730 | |||
244ad15c92 | |||
586f45e634 | |||
b1b4743663 | |||
5600b4a2d3 | |||
9261167a1f | |||
519654e21b | |||
4840499a43 | |||
ee6cdf4ab3 | |||
98003f545d | |||
0046ed73c6 | |||
66a6475064 | |||
97804802c0 | |||
c9296a9a45 | |||
64a41c2601 | |||
0af6ae1be4 | |||
6b06d92a59 |
@ -1 +0,0 @@
|
|||||||
; needs to exist otherwise `$ coveralls` fails
|
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -2,12 +2,12 @@
|
|||||||
.idea/
|
.idea/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
dist/
|
dist/
|
||||||
httpie.egg-info/
|
|
||||||
build/
|
build/
|
||||||
*.egg-info
|
*.egg-info
|
||||||
.cache/
|
.cache/
|
||||||
.tox
|
.tox/
|
||||||
.coverage
|
.coverage
|
||||||
*.pyc
|
*.pyc
|
||||||
*.egg
|
*.egg
|
||||||
htmlcov
|
htmlcov
|
||||||
|
.pytest_cache/
|
||||||
|
128
.travis.yml
128
.travis.yml
@ -1,94 +1,96 @@
|
|||||||
# https://travis-ci.org/jkbrzt/httpie
|
# <https://travis-ci.org/jakubroztocil/httpie>
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
language: python
|
language: python
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- NEWEST_PYTHON=3.5
|
- NEWEST_PYTHON=3.7
|
||||||
|
|
||||||
python:
|
python:
|
||||||
- 2.6
|
# <https://docs.travis-ci.com/user/languages/python/>
|
||||||
|
|
||||||
- 2.7
|
- 2.7
|
||||||
- pypy
|
|
||||||
- 3.4
|
# Python 3.4 fails installing packages
|
||||||
|
# <https://travis-ci.org/jakubroztocil/httpie/jobs/403263566#L636>
|
||||||
|
# - 3.4
|
||||||
|
|
||||||
- 3.5
|
- 3.5
|
||||||
# Currently fails because of a Flask issue
|
- 3.6
|
||||||
# - pypy3
|
# - 3.7 # is done in the matrix below as described in travis-ci/travis-ci#9069
|
||||||
|
- pypy
|
||||||
|
|
||||||
|
# pypy3 currently fails because of a Flask issue
|
||||||
|
# - pypy3
|
||||||
|
|
||||||
|
cache: pip
|
||||||
matrix:
|
matrix:
|
||||||
|
|
||||||
include:
|
include:
|
||||||
|
# Add manually defined OS X builds
|
||||||
# Manually defined OS X builds
|
# <https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages)>
|
||||||
# https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages)
|
|
||||||
|
|
||||||
# Stock OSX Python
|
|
||||||
- os: osx
|
- os: osx
|
||||||
language: generic
|
language: generic
|
||||||
env:
|
env:
|
||||||
|
# Stock OSX Python
|
||||||
|
- TOXENV=py27-osx-builtin
|
||||||
|
- BREW_PYTHON_PACKAGE=
|
||||||
|
- os: osx
|
||||||
|
language: generic
|
||||||
|
env:
|
||||||
|
# Latest Python 2.7 from Homebrew
|
||||||
- TOXENV=py27
|
- TOXENV=py27
|
||||||
|
- BREW_PYTHON_PACKAGE=python@2
|
||||||
# Latest Python 2.x from Homebrew
|
|
||||||
- os: osx
|
- os: osx
|
||||||
language: generic
|
language: generic
|
||||||
env:
|
env:
|
||||||
- TOXENV=py27
|
# Latest Python 3.x from Homebrew
|
||||||
- BREW_INSTALL=python
|
- TOXENV=py37 # <= needs to be kept up-to-date to reflect latest minor version
|
||||||
|
- BREW_PYTHON_PACKAGE=python@3
|
||||||
# Latest Python 3.x from Homebrew
|
# Travis Python 3.7 must run sudo on
|
||||||
- os: osx
|
|
||||||
language: generic
|
|
||||||
env:
|
|
||||||
- TOXENV=py35
|
|
||||||
- BREW_INSTALL=python3
|
|
||||||
|
|
||||||
# Python Codestyle
|
|
||||||
- os: linux
|
- os: linux
|
||||||
python: 3.5
|
python: 3.7
|
||||||
env: CODESTYLE=true
|
env: TOXENV=py37
|
||||||
|
sudo: true # Required for Python 3.7
|
||||||
|
dist: xenial # Required for Python 3.7
|
||||||
|
# Add a codestyle-only build
|
||||||
|
- os: linux
|
||||||
|
python: 3.6
|
||||||
|
env: CODESTYLE_ONLY=true
|
||||||
install:
|
install:
|
||||||
- |
|
- |
|
||||||
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
|
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
|
||||||
if [[ -n "$BREW_INSTALL" ]]; then
|
if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then
|
||||||
brew update
|
brew update
|
||||||
brew install "$BREW_INSTALL"
|
if ! brew list --versions "$BREW_PYTHON_PACKAGE" >/dev/null; then
|
||||||
|
brew install "$BREW_PYTHON_PACKAGE"
|
||||||
|
elif ! brew outdated "$BREW_PYTHON_PACKAGE"; then
|
||||||
|
brew upgrade "$BREW_PYTHON_PACKAGE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
sudo pip2 install tox
|
||||||
fi
|
fi
|
||||||
sudo pip install tox
|
|
||||||
fi
|
|
||||||
if [[ $CODESTYLE ]]; then
|
|
||||||
pip install pycodestyle
|
|
||||||
fi
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||||
if [[ $CODESTYLE ]]; then
|
if [[ $CODESTYLE_ONLY ]]; then
|
||||||
# 241 - multiple spaces after ‘,’
|
make pycodestyle
|
||||||
# 501 - line too long
|
else
|
||||||
pycodestyle --ignore=E241,E501
|
make test
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
make
|
PATH="/usr/local/bin:$PATH" tox -e "$TOXENV"
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
PATH="/usr/local/bin:$PATH" tox -e "$TOXENV"
|
|
||||||
fi
|
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- |
|
- |
|
||||||
if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux' ]]; then
|
if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||||
pip install python-coveralls && coveralls
|
make coveralls
|
||||||
fi
|
fi
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
|
|
||||||
webhooks:
|
webhooks:
|
||||||
|
# options: [always|never|change] default: always
|
||||||
|
on_success: always
|
||||||
|
on_failure: always
|
||||||
|
on_start: always
|
||||||
urls:
|
urls:
|
||||||
# https://gitter.im/jkbrzt/httpie
|
# https://gitter.im/jkbrzt/httpie
|
||||||
- https://webhooks.gitter.im/e/c42fcd359a110d02830b
|
- https://webhooks.gitter.im/e/c42fcd359a110d02830b
|
||||||
on_success: always # options: [always|never|change] default: always
|
|
||||||
on_failure: always # options: [always|never|change] default: always
|
|
||||||
on_start: always # options: [always|never|change] default: always
|
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
HTTPie authors
|
HTTPie authors
|
||||||
==============
|
==============
|
||||||
|
|
||||||
* `Jakub Roztocil <https://github.com/jkbrzt>`_
|
* `Jakub Roztocil <https://github.com/jakubroztocil>`_
|
||||||
|
|
||||||
|
|
||||||
Patches and ideas
|
Patches and ideas
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
`Complete list of contributors on GitHub <https://github.com/jkbrzt/httpie/graphs/contributors>`_
|
`Complete list of contributors on GitHub <https://github.com/jakubroztocil/httpie/graphs/contributors>`_
|
||||||
|
|
||||||
* `Cláudia T. Delgado <https://github.com/claudiatd>`_ (logo)
|
* `Cláudia T. Delgado <https://github.com/claudiatd>`_ (logo)
|
||||||
* `Hank Gay <https://github.com/gthank>`_
|
* `Hank Gay <https://github.com/gthank>`_
|
||||||
|
@ -6,9 +6,26 @@ This document records all notable changes to `HTTPie <http://httpie.org>`_.
|
|||||||
This project adheres to `Semantic Versioning <http://semver.org/>`_.
|
This project adheres to `Semantic Versioning <http://semver.org/>`_.
|
||||||
|
|
||||||
|
|
||||||
`1.0.0-dev`_ (unreleased)
|
`1.0.0`_ (2018-11-02)
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
* Added ``--style=auto`` which follows the terminal ANSI color styles.
|
||||||
|
* Added support for selecting TLS 1.3 via ``--ssl=tls1.3``
|
||||||
|
(available once implemented in upstream libraries).
|
||||||
|
* Added ``true``/``false`` as valid values for ``--verify``
|
||||||
|
(in addition to ``yes``/``no``) and the boolean value is case-insensitive.
|
||||||
|
* Changed the default ``--style`` from ``solarized`` to ``auto`` (on Windows it stays ``fruity``).
|
||||||
|
* Fixed default headers being incorrectly case-sensitive.
|
||||||
|
* Removed Python 2.6 support.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
`0.9.9`_ (2016-12-08)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
* Fixed README.
|
||||||
|
|
||||||
|
|
||||||
`0.9.8`_ (2016-12-08)
|
`0.9.8`_ (2016-12-08)
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
@ -92,8 +109,8 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
|
|||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
* Added support for Requests transport adapter plugins
|
* Added support for Requests transport adapter plugins
|
||||||
(see `httpie-unixsocket <https://github.com/msabramo/httpie-unixsocket>`_
|
(see `httpie-unixsocket <https://github.com/httpie/httpie-unixsocket>`_
|
||||||
and `httpie-http2 <https://github.com/jkbrzt/httpie-http2>`_)
|
and `httpie-http2 <https://github.com/httpie/httpie-http2>`_)
|
||||||
|
|
||||||
|
|
||||||
`0.9.0`_ (2015-01-31)
|
`0.9.0`_ (2015-01-31)
|
||||||
@ -297,29 +314,30 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
|
|||||||
* Initial public release
|
* Initial public release
|
||||||
|
|
||||||
|
|
||||||
.. _`0.1`: https://github.com/jkbrzt/httpie/commit/b966efa
|
.. _`0.1`: https://github.com/jakubroztocil/httpie/commit/b966efa
|
||||||
.. _0.1.4: https://github.com/jkbrzt/httpie/compare/b966efa...0.1.4
|
.. _0.1.4: https://github.com/jakubroztocil/httpie/compare/b966efa...0.1.4
|
||||||
.. _0.1.5: https://github.com/jkbrzt/httpie/compare/0.1.4...0.1.5
|
.. _0.1.5: https://github.com/jakubroztocil/httpie/compare/0.1.4...0.1.5
|
||||||
.. _0.1.6: https://github.com/jkbrzt/httpie/compare/0.1.5...0.1.6
|
.. _0.1.6: https://github.com/jakubroztocil/httpie/compare/0.1.5...0.1.6
|
||||||
.. _0.2.0: https://github.com/jkbrzt/httpie/compare/0.1.6...0.2.0
|
.. _0.2.0: https://github.com/jakubroztocil/httpie/compare/0.1.6...0.2.0
|
||||||
.. _0.2.1: https://github.com/jkbrzt/httpie/compare/0.2.0...0.2.1
|
.. _0.2.1: https://github.com/jakubroztocil/httpie/compare/0.2.0...0.2.1
|
||||||
.. _0.2.2: https://github.com/jkbrzt/httpie/compare/0.2.1...0.2.2
|
.. _0.2.2: https://github.com/jakubroztocil/httpie/compare/0.2.1...0.2.2
|
||||||
.. _0.2.5: https://github.com/jkbrzt/httpie/compare/0.2.2...0.2.5
|
.. _0.2.5: https://github.com/jakubroztocil/httpie/compare/0.2.2...0.2.5
|
||||||
.. _0.2.6: https://github.com/jkbrzt/httpie/compare/0.2.5...0.2.6
|
.. _0.2.6: https://github.com/jakubroztocil/httpie/compare/0.2.5...0.2.6
|
||||||
.. _0.2.7: https://github.com/jkbrzt/httpie/compare/0.2.5...0.2.7
|
.. _0.2.7: https://github.com/jakubroztocil/httpie/compare/0.2.5...0.2.7
|
||||||
.. _0.3.0: https://github.com/jkbrzt/httpie/compare/0.2.7...0.3.0
|
.. _0.3.0: https://github.com/jakubroztocil/httpie/compare/0.2.7...0.3.0
|
||||||
.. _0.4.0: https://github.com/jkbrzt/httpie/compare/0.3.0...0.4.0
|
.. _0.4.0: https://github.com/jakubroztocil/httpie/compare/0.3.0...0.4.0
|
||||||
.. _0.4.1: https://github.com/jkbrzt/httpie/compare/0.4.0...0.4.1
|
.. _0.4.1: https://github.com/jakubroztocil/httpie/compare/0.4.0...0.4.1
|
||||||
.. _0.5.0: https://github.com/jkbrzt/httpie/compare/0.4.1...0.5.0
|
.. _0.5.0: https://github.com/jakubroztocil/httpie/compare/0.4.1...0.5.0
|
||||||
.. _0.5.1: https://github.com/jkbrzt/httpie/compare/0.5.0...0.5.1
|
.. _0.5.1: https://github.com/jakubroztocil/httpie/compare/0.5.0...0.5.1
|
||||||
.. _0.6.0: https://github.com/jkbrzt/httpie/compare/0.5.1...0.6.0
|
.. _0.6.0: https://github.com/jakubroztocil/httpie/compare/0.5.1...0.6.0
|
||||||
.. _0.7.1: https://github.com/jkbrzt/httpie/compare/0.6.0...0.7.1
|
.. _0.7.1: https://github.com/jakubroztocil/httpie/compare/0.6.0...0.7.1
|
||||||
.. _0.8.0: https://github.com/jkbrzt/httpie/compare/0.7.1...0.8.0
|
.. _0.8.0: https://github.com/jakubroztocil/httpie/compare/0.7.1...0.8.0
|
||||||
.. _0.9.0: https://github.com/jkbrzt/httpie/compare/0.8.0...0.9.0
|
.. _0.9.0: https://github.com/jakubroztocil/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.1: https://github.com/jakubroztocil/httpie/compare/0.9.0...0.9.1
|
||||||
.. _0.9.2: https://github.com/jkbrzt/httpie/compare/0.9.1...0.9.2
|
.. _0.9.2: https://github.com/jakubroztocil/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.3: https://github.com/jakubroztocil/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.4: https://github.com/jakubroztocil/httpie/compare/0.9.3...0.9.4
|
||||||
.. _0.9.6: https://github.com/jkbrzt/httpie/compare/0.9.4...0.9.6
|
.. _0.9.6: https://github.com/jakubroztocil/httpie/compare/0.9.4...0.9.6
|
||||||
.. _0.9.8: https://github.com/jkbrzt/httpie/compare/0.9.6...0.9.8
|
.. _0.9.8: https://github.com/jakubroztocil/httpie/compare/0.9.6...0.9.8
|
||||||
.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.8...master
|
.. _0.9.9: https://github.com/jakubroztocil/httpie/compare/0.9.8...0.9.9
|
||||||
|
.. _1.0.0: https://github.com/jakubroztocil/httpie/compare/0.9.9...1.0.0
|
||||||
|
@ -25,14 +25,14 @@ to your bug report, e.g.:
|
|||||||
|
|
||||||
Before working on a new feature or a bug, please browse `existing issues`_
|
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
|
to see whether it has been previously discussed. If the change in question
|
||||||
is a bigger one, it's always good to discuss before your starting working on
|
is a bigger one, it's always good to discuss before you start working on
|
||||||
it.
|
it.
|
||||||
|
|
||||||
|
|
||||||
Creating Development Environment
|
Creating Development Environment
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
Go to https://github.com/jkbrzt/httpie and fork the project repository.
|
Go to https://github.com/jakubroztocil/httpie and fork the project repository.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -47,13 +47,14 @@ Go to https://github.com/jkbrzt/httpie and fork the project repository.
|
|||||||
|
|
||||||
# Install dev. requirements and also HTTPie (in editable mode
|
# Install dev. requirements and also HTTPie (in editable mode
|
||||||
# so that the `http' command will point to your working copy):
|
# so that the `http' command will point to your working copy):
|
||||||
make
|
make init
|
||||||
|
|
||||||
|
|
||||||
Making Changes
|
Making Changes
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8).
|
Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8)
|
||||||
|
and that ``make pycodestyle`` passes.
|
||||||
|
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
@ -71,18 +72,18 @@ Running all tests:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
# Run all tests on the current Python interpreter
|
# Run all tests on the current Python interpreter with coverage
|
||||||
make test
|
make test
|
||||||
|
|
||||||
# Run all tests on the current Python with coverage
|
|
||||||
make test-cover
|
|
||||||
|
|
||||||
# Run all tests in all of the supported and available Pythons via Tox
|
# Run all tests in all of the supported and available Pythons via Tox
|
||||||
make test-tox
|
make test-tox
|
||||||
|
|
||||||
# Run all tests for code as well as packaging, etc.
|
# Run all tests for code as well as packaging, etc.
|
||||||
make test-all
|
make test-all
|
||||||
|
|
||||||
|
# Test PEP8 compliance
|
||||||
|
make pycodestyle
|
||||||
|
|
||||||
|
|
||||||
Running specific tests:
|
Running specific tests:
|
||||||
***********************
|
***********************
|
||||||
@ -95,11 +96,11 @@ Running specific tests:
|
|||||||
py.test tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok
|
py.test tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok
|
||||||
|
|
||||||
# Run specific tests on the on all Pythons via Tox
|
# Run specific tests on the on all Pythons via Tox
|
||||||
|
# (change to `tox -e py37' to limit Python version)
|
||||||
tox -- tests/test_uploads.py --verbose
|
tox -- tests/test_uploads.py --verbose
|
||||||
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload --verbose
|
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload --verbose
|
||||||
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok --verbose
|
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok --verbose
|
||||||
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
See `Makefile`_ for additional development utilities.
|
See `Makefile`_ for additional development utilities.
|
||||||
@ -107,10 +108,10 @@ Don't forget to add yourself to `AUTHORS`_!
|
|||||||
|
|
||||||
|
|
||||||
.. _Tox: http://tox.testrun.org
|
.. _Tox: http://tox.testrun.org
|
||||||
.. _supported Python environments: https://github.com/jkbrzt/httpie/blob/master/tox.ini
|
.. _supported Python environments: https://github.com/jakubroztocil/httpie/blob/master/tox.ini
|
||||||
.. _existing issues: https://github.com/jkbrzt/httpie/issues?state=open
|
.. _existing issues: https://github.com/jakubroztocil/httpie/issues?state=open
|
||||||
.. _AUTHORS: https://github.com/jkbrzt/httpie/blob/master/AUTHORS.rst
|
.. _AUTHORS: https://github.com/jakubroztocil/httpie/blob/master/AUTHORS.rst
|
||||||
.. _Makefile: https://github.com/jkbrzt/httpie/blob/master/Makefile
|
.. _Makefile: https://github.com/jakubroztocil/httpie/blob/master/Makefile
|
||||||
.. _pytest: http://pytest.org/
|
.. _pytest: http://pytest.org/
|
||||||
.. _Style Guide for Python Code: http://python.org/dev/peps/pep-0008/
|
.. _Style Guide for Python Code: http://python.org/dev/peps/pep-0008/
|
||||||
.. _test suite: https://github.com/jkbrzt/httpie/tree/master/tests
|
.. _test suite: https://github.com/jakubroztocil/httpie/tree/master/tests
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
|||||||
Copyright © 2012-2016 Jakub Roztocil <jakub@roztocil.co>
|
Copyright © 2012-2017 Jakub Roztocil <jakub@roztocil.co>
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
57
Makefile
57
Makefile
@ -1,6 +1,6 @@
|
|||||||
#
|
###############################################################################
|
||||||
# See ./CONTRIBUTING.rst
|
# See ./CONTRIBUTING.rst
|
||||||
#
|
###############################################################################
|
||||||
|
|
||||||
VERSION=$(shell grep __version__ httpie/__init__.py)
|
VERSION=$(shell grep __version__ httpie/__init__.py)
|
||||||
REQUIREMENTS="requirements-dev.txt"
|
REQUIREMENTS="requirements-dev.txt"
|
||||||
@ -20,6 +20,17 @@ init: uninstall-httpie
|
|||||||
|
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo $(TAG)Cleaning up$(END)
|
||||||
|
rm -rf .tox *.egg dist build .coverage .cache .pytest_cache httpie.egg-info
|
||||||
|
find . -name '__pycache__' -delete -print -o -name '*.pyc' -delete -print
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Testing
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
test: init
|
test: init
|
||||||
@echo $(TAG)Running tests on the current Python interpreter with coverage $(END)
|
@echo $(TAG)Running tests on the current Python interpreter with coverage $(END)
|
||||||
@ -27,9 +38,8 @@ test: init
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
test-tox: init
|
# test-all is meant to test everything — even this Makefile
|
||||||
@echo $(TAG)Running tests on all Pythons via Tox$(END)
|
test-all: uninstall-all clean init test test-tox test-dist pycodestyle
|
||||||
tox
|
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +47,12 @@ test-dist: test-sdist test-bdist-wheel
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
test-tox: init
|
||||||
|
@echo $(TAG)Running tests on all Pythons via Tox$(END)
|
||||||
|
tox
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
test-sdist: clean uninstall-httpie
|
test-sdist: clean uninstall-httpie
|
||||||
@echo $(TAG)Testing sdist build an installation$(END)
|
@echo $(TAG)Testing sdist build an installation$(END)
|
||||||
python setup.py sdist
|
python setup.py sdist
|
||||||
@ -53,12 +69,26 @@ test-bdist-wheel: clean uninstall-httpie
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
# This tests everything, even this Makefile.
|
pycodestyle:
|
||||||
test-all: uninstall-all clean init test test-tox test-dist
|
which pycodestyle || pip install pycodestyle
|
||||||
|
pycodestyle
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
coveralls:
|
||||||
|
which coveralls || pip install python-coveralls
|
||||||
|
coveralls
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Publishing to PyPi
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
publish: test-all publish-no-test
|
publish: test-all publish-no-test
|
||||||
|
|
||||||
|
|
||||||
publish-no-test:
|
publish-no-test:
|
||||||
@echo $(TAG)Testing wheel build an installation$(END)
|
@echo $(TAG)Testing wheel build an installation$(END)
|
||||||
@echo "$(VERSION)"
|
@echo "$(VERSION)"
|
||||||
@ -69,12 +99,10 @@ publish-no-test:
|
|||||||
@echo
|
@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
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Uninstalling
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
uninstall-httpie:
|
uninstall-httpie:
|
||||||
@echo $(TAG)Uninstalling httpie$(END)
|
@echo $(TAG)Uninstalling httpie$(END)
|
||||||
@ -96,5 +124,10 @@ uninstall-all: uninstall-httpie
|
|||||||
- pip uninstall --yes -r $(REQUIREMENTS)
|
- pip uninstall --yes -r $(REQUIREMENTS)
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Utils
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
homebrew-formula-vars:
|
homebrew-formula-vars:
|
||||||
extras/get-homebrew-formula-vars.py
|
extras/get-homebrew-formula-vars.py
|
||||||
|
215
README.rst
215
README.rst
@ -11,7 +11,7 @@ generally interacting with HTTP servers.
|
|||||||
|
|
||||||
.. class:: no-web
|
.. class:: no-web
|
||||||
|
|
||||||
.. image:: https://raw.githubusercontent.com/jkbrzt/httpie/master/httpie.png
|
.. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.png
|
||||||
:alt: HTTPie compared to cURL
|
:alt: HTTPie compared to cURL
|
||||||
:width: 100%
|
:width: 100%
|
||||||
:align: center
|
:align: center
|
||||||
@ -19,7 +19,7 @@ generally interacting with HTTP servers.
|
|||||||
|
|
||||||
.. class:: no-web no-pdf
|
.. class:: no-web no-pdf
|
||||||
|
|
||||||
|pypi| |unix_build| |windows_build| |coverage| |gitter|
|
|pypi| |unix_build| |coverage| |gitter|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -27,9 +27,6 @@ generally interacting with HTTP servers.
|
|||||||
|
|
||||||
.. section-numbering::
|
.. section-numbering::
|
||||||
|
|
||||||
.. raw:: pdf
|
|
||||||
|
|
||||||
PageBreak oneColumn
|
|
||||||
|
|
||||||
|
|
||||||
Main features
|
Main features
|
||||||
@ -44,8 +41,8 @@ Main features
|
|||||||
* Custom headers
|
* Custom headers
|
||||||
* Persistent sessions
|
* Persistent sessions
|
||||||
* Wget-like downloads
|
* Wget-like downloads
|
||||||
* Python 2.6, 2.7 and 3.x support
|
* Python 2.7 and 3.x support
|
||||||
* Linux, Mac OS X and Windows support
|
* Linux, macOS and Windows support
|
||||||
* Plugins
|
* Plugins
|
||||||
* Documentation
|
* Documentation
|
||||||
* Test coverage
|
* Test coverage
|
||||||
@ -77,16 +74,25 @@ Linux
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
Most Linux distributions provide a package that can be installed using the
|
Most Linux distributions provide a package that can be installed using the
|
||||||
system package manager, e.g.:
|
system package manager, for example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
# Debian-based distributions such as Ubuntu:
|
# Debian, Ubuntu, etc.
|
||||||
$ apt-get install httpie
|
$ apt-get install httpie
|
||||||
|
|
||||||
# RPM-based distributions:
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Fedora
|
||||||
|
$ dnf install httpie
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# CentOS, RHEL, ...
|
||||||
$ yum install httpie
|
$ yum install httpie
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
# Arch Linux
|
# Arch Linux
|
||||||
$ pacman -S httpie
|
$ pacman -S httpie
|
||||||
|
|
||||||
@ -110,31 +116,51 @@ and always provides the latest version) is to use `pip`_:
|
|||||||
``easy_install httpie`` as a fallback.)
|
``easy_install httpie`` as a fallback.)
|
||||||
|
|
||||||
|
|
||||||
Development version
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
The latest development version can be installed directly from GitHub:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
# Mac OS X via Homebrew
|
|
||||||
$ brew install httpie --HEAD
|
|
||||||
|
|
||||||
# Universal
|
|
||||||
$ pip install --upgrade https://github.com/jkbrzt/httpie/archive/master.tar.gz
|
|
||||||
|
|
||||||
|
|
||||||
Python version
|
Python version
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Although Python 2.6 and 2.7 are supported as well, it is recommended to install
|
Although Python 2.7 is supported as well, it is strongly recommended to
|
||||||
HTTPie against the latest Python 3.x whenever possible. That will ensure that
|
install HTTPie against the latest Python 3.x whenever possible. That will
|
||||||
some of the newer HTTP features, such as `SNI (Server Name Indication)`_,
|
ensure that some of the newer HTTP features, such as
|
||||||
work out of the box.
|
`SNI (Server Name Indication)`_, work out of the box.
|
||||||
Python 3 is the default for Homebrew installations starting with version 0.9.4.
|
Python 3 is the default for Homebrew installations starting with version 0.9.4.
|
||||||
To see which version HTTPie uses, run ``http --debug``.
|
To see which version HTTPie uses, run ``http --debug``.
|
||||||
|
|
||||||
|
|
||||||
|
Unstable version
|
||||||
|
----------------
|
||||||
|
|
||||||
|
You can also install the latest unreleased development version directly from
|
||||||
|
the ``master`` branch on GitHub. It is a work-in-progress of a future stable
|
||||||
|
release so the experience might be not as smooth.
|
||||||
|
|
||||||
|
|unix_build|
|
||||||
|
|
||||||
|
|
||||||
|
On macOS you can install it with Homebrew:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ brew install httpie --HEAD
|
||||||
|
|
||||||
|
|
||||||
|
Otherwise with ``pip``:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ pip install --upgrade https://github.com/jakubroztocil/httpie/archive/master.tar.gz
|
||||||
|
|
||||||
|
|
||||||
|
Verify that now we have the
|
||||||
|
`current development version identifier <https://github.com/jakubroztocil/httpie/blob/0af6ae1be444588bbc4747124e073423151178a0/httpie/__init__.py#L5>`_
|
||||||
|
with the ``-dev`` suffix, for example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ http --version
|
||||||
|
1.0.0-dev
|
||||||
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
=====
|
=====
|
||||||
|
|
||||||
@ -182,12 +208,12 @@ See the request that is being sent using one of the `output options`_:
|
|||||||
|
|
||||||
|
|
||||||
Use `Github API`_ to post a comment on an
|
Use `Github API`_ to post a comment on an
|
||||||
`issue <https://github.com/jkbrzt/httpie/issues/83>`_
|
`issue <https://github.com/jakubroztocil/httpie/issues/83>`_
|
||||||
with `authentication`_:
|
with `authentication`_:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ http -a USERNAME POST https://api.github.com/repos/jkbrzt/httpie/issues/83/comments body='HTTPie is awesome! :heart:'
|
$ http -a USERNAME POST https://api.github.com/repos/jakubroztocil/httpie/issues/83/comments body='HTTPie is awesome! :heart:'
|
||||||
|
|
||||||
|
|
||||||
Upload a file using `redirected input`_:
|
Upload a file using `redirected input`_:
|
||||||
@ -261,7 +287,7 @@ and can be omitted from the argument – ``http example.org`` works just fine.
|
|||||||
Querystring parameters
|
Querystring parameters
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
If you find yourself manually constructing URLs with
|
If you find yourself manually constructing URLs with querystring parameters
|
||||||
on the terminal, you may appreciate the ``param==value`` syntax for appending
|
on the terminal, you may appreciate the ``param==value`` syntax for appending
|
||||||
URL parameters. With that, you don't have to worry about escaping the ``&``
|
URL parameters. With that, you don't have to worry about escaping the ``&``
|
||||||
separators for your shell. Also, special characters in parameter values,
|
separators for your shell. Also, special characters in parameter values,
|
||||||
@ -372,8 +398,7 @@ their type is distinguished only by the separator used:
|
|||||||
|
|
||||||
|
|
||||||
Note that data fields aren't the only way to specify request data:
|
Note that data fields aren't the only way to specify request data:
|
||||||
`Redirected input`_ is a mechanism for passing arbitrary data request
|
`Redirected input`_ is a mechanism for passing arbitrary request data.
|
||||||
request.
|
|
||||||
|
|
||||||
|
|
||||||
Escaping rules
|
Escaping rules
|
||||||
@ -400,7 +425,7 @@ token ``--`` to prevent confusion with ``--arguments``:
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"-name-starting-with-dash": "value"
|
"-name-starting-with-dash": "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -409,7 +434,7 @@ JSON
|
|||||||
====
|
====
|
||||||
|
|
||||||
JSON is the *lingua franca* of modern web services and it is also the
|
JSON is the *lingua franca* of modern web services and it is also the
|
||||||
**implicit content type** HTTPie by default uses.
|
**implicit content type** HTTPie uses by default.
|
||||||
|
|
||||||
|
|
||||||
Simple example:
|
Simple example:
|
||||||
@ -594,7 +619,7 @@ There are a couple of default headers that HTTPie sets:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Any of those—except for ``Host``—can be overwritten and some of them unset.
|
Any of these except ``Host`` can be overwritten and some of them unset.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -618,6 +643,53 @@ To send a header with an empty value, use ``Header;``:
|
|||||||
$ http httpbin.org/headers 'Header;'
|
$ http httpbin.org/headers 'Header;'
|
||||||
|
|
||||||
|
|
||||||
|
Cookies
|
||||||
|
=======
|
||||||
|
|
||||||
|
HTTP clients send cookies to the server as regular `HTTP headers`_. That means,
|
||||||
|
HTTPie does not offer any special syntax for specifying cookies — the usual
|
||||||
|
``Header:Value`` notation is used:
|
||||||
|
|
||||||
|
|
||||||
|
Send a single cookie:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ http example.org Cookie:sessionid=foo
|
||||||
|
|
||||||
|
.. code-block:: http
|
||||||
|
|
||||||
|
GET / HTTP/1.1
|
||||||
|
Accept: */*
|
||||||
|
Accept-Encoding: gzip, deflate
|
||||||
|
Connection: keep-alive
|
||||||
|
Cookie: sessionid=foo
|
||||||
|
Host: example.org
|
||||||
|
User-Agent: HTTPie/0.9.9
|
||||||
|
|
||||||
|
|
||||||
|
Send multiple cookies
|
||||||
|
(note the header is quoted to prevent the shell from interpreting the ``;``):
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ http example.org 'Cookie:sessionid=foo;another-cookie=bar'
|
||||||
|
|
||||||
|
.. code-block:: http
|
||||||
|
|
||||||
|
GET / HTTP/1.1
|
||||||
|
Accept: */*
|
||||||
|
Accept-Encoding: gzip, deflate
|
||||||
|
Connection: keep-alive
|
||||||
|
Cookie: sessionid=foo;another-cookie=bar
|
||||||
|
Host: example.org
|
||||||
|
User-Agent: HTTPie/0.9.9
|
||||||
|
|
||||||
|
|
||||||
|
If you often deal with cookies in your requests, then chances are you'd appreciate
|
||||||
|
the `sessions`_ feature.
|
||||||
|
|
||||||
|
|
||||||
Authentication
|
Authentication
|
||||||
==============
|
==============
|
||||||
|
|
||||||
@ -670,7 +742,7 @@ Password prompt
|
|||||||
``.netrc``
|
``.netrc``
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Authorization information from your ``~/.netrc`` file is honored as well:
|
Authentication information from your ``~/.netrc`` file is honored as well:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@ -791,7 +863,7 @@ In your ``~/.bash_profile``:
|
|||||||
SOCKS
|
SOCKS
|
||||||
-----
|
-----
|
||||||
|
|
||||||
To enable SOCKS proxy support please install ``requests[socks]`` using ``pip``:
|
Homebrew-installed HTTPie comes with SOCKS proxy support out of the box. To enable SOCKS proxy support for non-Homebrew installations, you'll need to install ``requests[socks]`` manually using ``pip``:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -855,7 +927,7 @@ SSL version
|
|||||||
Use the ``--ssl=<PROTOCOL>`` to specify the desired protocol version to use.
|
Use the ``--ssl=<PROTOCOL>`` to specify the desired protocol version to use.
|
||||||
This will default to SSL v2.3 which will negotiate the highest protocol that both
|
This will default to SSL v2.3 which will negotiate the highest protocol that both
|
||||||
the server and your installation of OpenSSL support. The available protocols
|
the server and your installation of OpenSSL support. The available protocols
|
||||||
are ``ssl2.3``, ``ssl3``, ``tls1``, ``tls1.1``, ``tls1.2``. (The actually
|
are ``ssl2.3``, ``ssl3``, ``tls1``, ``tls1.1``, ``tls1.2``, ``tls1.3``. (The actually
|
||||||
available set of protocols may vary depending on your OpenSSL installation.)
|
available set of protocols may vary depending on your OpenSSL installation.)
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -895,7 +967,7 @@ be printed via several options:
|
|||||||
``--headers, -h`` Only the response headers are printed.
|
``--headers, -h`` Only the response headers are printed.
|
||||||
``--body, -b`` Only the response body is printed.
|
``--body, -b`` Only the response body is printed.
|
||||||
``--verbose, -v`` Print the whole HTTP exchange (request and response).
|
``--verbose, -v`` Print the whole HTTP exchange (request and response).
|
||||||
This option also enables ``--all`` (see bellow).
|
This option also enables ``--all`` (see below).
|
||||||
``--print, -p`` Selects parts of the HTTP exchange.
|
``--print, -p`` Selects parts of the HTTP exchange.
|
||||||
================= =====================================================
|
================= =====================================================
|
||||||
|
|
||||||
@ -1035,7 +1107,7 @@ You can even pipe web services together using HTTPie:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ http GET https://api.github.com/repos/jkbrzt/httpie | http POST httpbin.org/post
|
$ http GET https://api.github.com/repos/jakubroztocil/httpie | http POST httpbin.org/post
|
||||||
|
|
||||||
|
|
||||||
You can use ``cat`` to enter multiline data on the terminal:
|
You can use ``cat`` to enter multiline data on the terminal:
|
||||||
@ -1212,7 +1284,7 @@ is being saved to a file.
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ http --download https://github.com/jkbrzt/httpie/archive/master.tar.gz
|
$ http --download https://github.com/jakubroztocil/httpie/archive/master.tar.gz
|
||||||
|
|
||||||
.. code-block:: http
|
.. code-block:: http
|
||||||
|
|
||||||
@ -1242,7 +1314,7 @@ headers and progress are still shown in the terminal:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ http -d https://github.com/jkbrzt/httpie/archive/master.tar.gz | tar zxf -
|
$ http -d https://github.com/jakubroztocil/httpie/archive/master.tar.gz | tar zxf -
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1320,8 +1392,8 @@ previous ones to the same host.
|
|||||||
|
|
||||||
However, HTTPie also supports persistent
|
However, HTTPie also supports persistent
|
||||||
sessions via the ``--session=SESSION_NAME_OR_PATH`` option. In a session,
|
sessions via the ``--session=SESSION_NAME_OR_PATH`` option. In a session,
|
||||||
custom headers—except for the ones starting with ``Content-`` or ``If-``—,
|
custom `HTTP headers`_ (except for the ones starting with ``Content-`` or ``If-``),
|
||||||
authorization, and cookies
|
`authentication`_, and `cookies`_
|
||||||
(manually specified or sent by the server) persist between requests
|
(manually specified or sent by the server) persist between requests
|
||||||
to the same host.
|
to the same host.
|
||||||
|
|
||||||
@ -1335,11 +1407,12 @@ to the same host.
|
|||||||
$ http --session=/tmp/session.json example.org
|
$ http --session=/tmp/session.json example.org
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All session data, including credentials, cookie data,
|
All session data, including credentials, cookie data,
|
||||||
and custom headers are stored in plain text.
|
and custom headers are stored in plain text.
|
||||||
That means session files can also be created and edited manually in a text
|
That means session files can also be created and edited manually in a text
|
||||||
editor—they are regular JSON.
|
editor—they are regular JSON. It also means that they can be read by anyone
|
||||||
|
who has access to the session file.
|
||||||
|
|
||||||
|
|
||||||
Named sessions
|
Named sessions
|
||||||
--------------
|
--------------
|
||||||
@ -1352,8 +1425,8 @@ you can create a new session named ``user1`` for ``example.org``:
|
|||||||
|
|
||||||
$ http --session=user1 -a user1:password example.org X-Foo:Bar
|
$ http --session=user1 -a user1:password example.org X-Foo:Bar
|
||||||
|
|
||||||
From now onw, you can refer to the session by its name. When you choose to
|
From now on, you can refer to the session by its name. When you choose to
|
||||||
use the session again, any the previously used authorization and HTTP headers
|
use the session again, any previously specified authentication or HTTP headers
|
||||||
will automatically be set:
|
will automatically be set:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -1488,7 +1561,7 @@ expecting that the request body will be passed through.
|
|||||||
And since there's no data nor ``EOF``, it will be stuck. So unless you're
|
And since there's no data nor ``EOF``, it will be stuck. So unless you're
|
||||||
piping some data to HTTPie, this flag should be used in scripts.
|
piping some data to HTTPie, this flag should be used in scripts.
|
||||||
|
|
||||||
Also, it's might be good to override the default ``30`` second ``--timeout`` to
|
Also, it might be good to override the default ``30`` second ``--timeout`` to
|
||||||
something that suits you.
|
something that suits you.
|
||||||
|
|
||||||
|
|
||||||
@ -1555,7 +1628,7 @@ Please use the following support channels:
|
|||||||
to ask questions (please make sure to use the
|
to ask questions (please make sure to use the
|
||||||
`httpie <http://stackoverflow.com/questions/tagged/httpie>`_ tag).
|
`httpie <http://stackoverflow.com/questions/tagged/httpie>`_ tag).
|
||||||
* Tweet directly to `@clihttp <https://twitter.com/clihttp>`_.
|
* Tweet directly to `@clihttp <https://twitter.com/clihttp>`_.
|
||||||
* You can also tweet directly to `@jkbrzt`_.
|
* You can also tweet directly to `@jakubroztocil`_.
|
||||||
|
|
||||||
|
|
||||||
Related projects
|
Related projects
|
||||||
@ -1585,16 +1658,25 @@ HTTPie plays exceptionally well with the following tools:
|
|||||||
and command syntax highlighting
|
and command syntax highlighting
|
||||||
|
|
||||||
|
|
||||||
|
Alternatives
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* `httpcat <https://github.com/jakubroztocil/httpcat>`_ — a lower-level sister utility
|
||||||
|
of HTTPie for constructing raw HTTP requests on the command line.
|
||||||
|
* `curl <https://curl.haxx.se>`_ — a "Swiss knife" command line tool and
|
||||||
|
an exceptional library for transferring data with URLs.
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
See `CONTRIBUTING.rst <https://github.com/jkbrzt/httpie/blob/master/CONTRIBUTING.rst>`_.
|
See `CONTRIBUTING.rst <https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst>`_.
|
||||||
|
|
||||||
|
|
||||||
Change log
|
Change log
|
||||||
----------
|
----------
|
||||||
|
|
||||||
See `CHANGELOG <https://github.com/jkbrzt/httpie/blob/master/CHANGELOG.rst>`_.
|
See `CHANGELOG <https://github.com/jakubroztocil/httpie/blob/master/CHANGELOG.rst>`_.
|
||||||
|
|
||||||
|
|
||||||
Artwork
|
Artwork
|
||||||
@ -1606,22 +1688,22 @@ See `claudiatd/httpie-artwork`_
|
|||||||
Licence
|
Licence
|
||||||
-------
|
-------
|
||||||
|
|
||||||
BSD-3-Clause: `LICENSE <https://github.com/jkbrzt/httpie/blob/master/LICENSE>`_.
|
BSD-3-Clause: `LICENSE <https://github.com/jakubroztocil/httpie/blob/master/LICENSE>`_.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Authors
|
Authors
|
||||||
-------
|
-------
|
||||||
|
|
||||||
`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_
|
`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_
|
||||||
have contributed.
|
have contributed.
|
||||||
|
|
||||||
|
|
||||||
.. _pip: http://www.pip-installer.org/en/latest/index.html
|
.. _pip: https://pip.pypa.io/en/stable/installing/
|
||||||
.. _Github API: http://developer.github.com/v3/issues/comments/#create-a-comment
|
.. _Github API: http://developer.github.com/v3/issues/comments/#create-a-comment
|
||||||
.. _these fine people: https://github.com/jkbrzt/httpie/contributors
|
.. _these fine people: https://github.com/jakubroztocil/httpie/contributors
|
||||||
.. _Jakub Roztocil: http://roztocil.co
|
.. _Jakub Roztocil: https://roztocil.co
|
||||||
.. _@jkbrzt: https://twitter.com/jkbrzt
|
.. _@jakubroztocil: https://twitter.com/jakubroztocil
|
||||||
.. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork
|
.. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork
|
||||||
|
|
||||||
|
|
||||||
@ -1629,19 +1711,14 @@ have contributed.
|
|||||||
:target: https://pypi.python.org/pypi/httpie
|
:target: https://pypi.python.org/pypi/httpie
|
||||||
:alt: Latest version released on PyPi
|
:alt: Latest version released on PyPi
|
||||||
|
|
||||||
.. |coverage| image:: https://img.shields.io/coveralls/jkbrzt/httpie/master.svg?style=flat-square&label=coverage
|
.. |coverage| image:: https://img.shields.io/coveralls/jakubroztocil/httpie/master.svg?style=flat-square&label=coverage
|
||||||
:target: https://coveralls.io/r/jkbrzt/httpie?branch=master
|
:target: https://coveralls.io/r/jakubroztocil/httpie?branch=master
|
||||||
:alt: Test coverage
|
:alt: Test coverage
|
||||||
|
|
||||||
.. |unix_build| image:: https://img.shields.io/travis/jkbrzt/httpie/master.svg?style=flat-square&label=unix%20build
|
.. |unix_build| image:: https://img.shields.io/travis/jakubroztocil/httpie/master.svg?style=flat-square&label=unix%20build
|
||||||
:target: http://travis-ci.org/jkbrzt/httpie
|
:target: http://travis-ci.org/jakubroztocil/httpie
|
||||||
:alt: Build status of the master branch on Mac/Linux
|
:alt: Build status of the master branch on Mac/Linux
|
||||||
|
|
||||||
.. |windows_build| image:: https://img.shields.io/appveyor/ci/jkbrzt/httpie.svg?style=flat-square&label=windows%20build
|
.. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square
|
||||||
:target: https://ci.appveyor.com/project/jkbrzt/httpie
|
|
||||||
:alt: Build status of the master branch on Windows
|
|
||||||
|
|
||||||
.. |gitter| image:: https://badges.gitter.im/jkbrzt/httpie.svg
|
|
||||||
:target: https://gitter.im/jkbrzt/httpie
|
:target: https://gitter.im/jkbrzt/httpie
|
||||||
:alt: Chat on Gitter
|
:alt: Chat on Gitter
|
||||||
|
|
||||||
|
23
appveyor.yml
23
appveyor.yml
@ -1,23 +0,0 @@
|
|||||||
# https://ci.appveyor.com/project/jkbrzt/httpie
|
|
||||||
build: false
|
|
||||||
|
|
||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- PYTHON: "C:/Python27"
|
|
||||||
# Python 3.4 has outdated pip
|
|
||||||
# - PYTHON: "C:/Python34"
|
|
||||||
- PYTHON: "C:/Python35"
|
|
||||||
|
|
||||||
init:
|
|
||||||
- "ECHO %PYTHON%"
|
|
||||||
- ps: "ls C:/Python*"
|
|
||||||
|
|
||||||
install:
|
|
||||||
# FIXME: updating pip fails with PermissionError
|
|
||||||
# - "%PYTHON%/Scripts/pip.exe install -U pip setuptools"
|
|
||||||
- "%PYTHON%/Scripts/pip.exe install -e ."
|
|
||||||
|
|
||||||
test_script:
|
|
||||||
- "%PYTHON%/Scripts/pip.exe --version"
|
|
||||||
- "%PYTHON%/Scripts/http.exe --debug"
|
|
||||||
- "%PYTHON%/python.exe setup.py test"
|
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""
|
"""
|
||||||
Generate URLs and file hashes to be included in the Homebrew formula
|
Generate URLs and file hashes to be included in the Homebrew formula
|
||||||
after a new release of HTTPie is published on PyPi.
|
after a new release of HTTPie has been published on PyPi.
|
||||||
|
|
||||||
https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb
|
https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ PACKAGES = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_info(package_name):
|
def get_package_meta(package_name):
|
||||||
api_url = 'https://pypi.python.org/pypi/{}/json'.format(package_name)
|
api_url = 'https://pypi.python.org/pypi/{}/json'.format(package_name)
|
||||||
resp = requests.get(api_url).json()
|
resp = requests.get(api_url).json()
|
||||||
hasher = hashlib.sha256()
|
hasher = hashlib.sha256()
|
||||||
@ -35,21 +35,23 @@ def get_info(package_name):
|
|||||||
'{}: download not found: {}'.format(package_name, resp))
|
'{}: download not found: {}'.format(package_name, resp))
|
||||||
|
|
||||||
|
|
||||||
packages = {
|
def main():
|
||||||
package_name: get_info(package_name) for package_name in PACKAGES
|
package_meta_map = {
|
||||||
}
|
package_name: get_package_meta(package_name)
|
||||||
|
for package_name in PACKAGES
|
||||||
|
}
|
||||||
|
httpie_meta = package_meta_map.pop('httpie')
|
||||||
|
print()
|
||||||
|
print(' url "{url}"'.format(url=httpie_meta['url']))
|
||||||
|
print(' sha256 "{sha256}"'.format(sha256=httpie_meta['sha256']))
|
||||||
|
print()
|
||||||
|
for dep_meta in package_meta_map.values():
|
||||||
|
print(' resource "{name}" do'.format(name=dep_meta['name']))
|
||||||
|
print(' url "{url}"'.format(url=dep_meta['url']))
|
||||||
|
print(' sha256 "{sha256}"'.format(sha256=dep_meta['sha256']))
|
||||||
|
print(' end')
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
httpie_info = packages.pop('httpie')
|
if __name__ == '__main__':
|
||||||
print("""
|
main()
|
||||||
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))
|
|
||||||
|
@ -30,11 +30,10 @@ function __fish_httpie_styles
|
|||||||
echo "xcode"
|
echo "xcode"
|
||||||
end
|
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 -x -c http -s s -l style -d 'Output coloring style (default is "monokai")' -A -a '(__fish_httpie_styles)'
|
||||||
complete -c http -s f -l form -d 'Data items from the command line are serialized as form fields'
|
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 -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 -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 -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 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 h -l headers -d 'Print only the response headers'
|
||||||
|
@ -11,7 +11,7 @@ class Httpie < Formula
|
|||||||
url "https://pypi.python.org/packages/85/95/7ccea3ae7fd1185e21629f6d14fa9c896d6250bb15fb492efa91edc741a2/httpie-0.9.8.tar.gz"
|
url "https://pypi.python.org/packages/85/95/7ccea3ae7fd1185e21629f6d14fa9c896d6250bb15fb492efa91edc741a2/httpie-0.9.8.tar.gz"
|
||||||
sha256 "515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1"
|
sha256 "515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1"
|
||||||
|
|
||||||
head "https://github.com/jkbrzt/httpie.git"
|
head "https://github.com/jakubroztocil/httpie.git"
|
||||||
|
|
||||||
depends_on :python3
|
depends_on :python3
|
||||||
|
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
HTTPie - a CLI, cURL-like tool for humans.
|
HTTPie - a CLI, cURL-like tool for humans.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
__version__ = '1.0.0'
|
||||||
__author__ = 'Jakub Roztocil'
|
__author__ = 'Jakub Roztocil'
|
||||||
__version__ = '0.9.8'
|
|
||||||
__licence__ = 'BSD'
|
__licence__ = 'BSD'
|
||||||
|
|
||||||
|
|
||||||
class ExitStatus:
|
class ExitStatus:
|
||||||
"""Exit status code constants."""
|
"""Program exit code constants."""
|
||||||
OK = 0
|
SUCCESS = 0
|
||||||
ERROR = 1
|
ERROR = 1
|
||||||
PLUGIN_ERROR = 7
|
PLUGIN_ERROR = 7
|
||||||
|
|
||||||
@ -25,8 +25,8 @@ class ExitStatus:
|
|||||||
ERROR_HTTP_5XX = 5
|
ERROR_HTTP_5XX = 5
|
||||||
|
|
||||||
|
|
||||||
EXIT_STATUS_LABELS = dict(
|
EXIT_STATUS_LABELS = {
|
||||||
(value, key)
|
value: key
|
||||||
for key, value in ExitStatus.__dict__.items()
|
for key, value in ExitStatus.__dict__.items()
|
||||||
if key.isupper()
|
if key.isupper()
|
||||||
)
|
}
|
||||||
|
@ -20,7 +20,9 @@ from httpie.input import (
|
|||||||
PRETTY_STDOUT_TTY_ONLY, SessionNameValidator,
|
PRETTY_STDOUT_TTY_ONLY, SessionNameValidator,
|
||||||
readable_file_arg, SSL_VERSION_ARG_MAPPING
|
readable_file_arg, SSL_VERSION_ARG_MAPPING
|
||||||
)
|
)
|
||||||
from httpie.output.formatters.colors import AVAILABLE_STYLES, DEFAULT_STYLE
|
from httpie.output.formatters.colors import (
|
||||||
|
AVAILABLE_STYLES, DEFAULT_STYLE, AUTO_STYLE
|
||||||
|
)
|
||||||
from httpie.plugins import plugin_manager
|
from httpie.plugins import plugin_manager
|
||||||
from httpie.plugins.builtin import BuiltinAuthPlugin
|
from httpie.plugins.builtin import BuiltinAuthPlugin
|
||||||
from httpie.sessions import DEFAULT_SESSIONS_DIR
|
from httpie.sessions import DEFAULT_SESSIONS_DIR
|
||||||
@ -46,6 +48,7 @@ class HTTPieHelpFormatter(RawDescriptionHelpFormatter):
|
|||||||
|
|
||||||
|
|
||||||
parser = HTTPieArgumentParser(
|
parser = HTTPieArgumentParser(
|
||||||
|
prog='http',
|
||||||
formatter_class=HTTPieHelpFormatter,
|
formatter_class=HTTPieHelpFormatter,
|
||||||
description='%s <http://httpie.org>' % __doc__.strip(),
|
description='%s <http://httpie.org>' % __doc__.strip(),
|
||||||
epilog=dedent("""
|
epilog=dedent("""
|
||||||
@ -54,7 +57,7 @@ parser = HTTPieArgumentParser(
|
|||||||
|
|
||||||
Suggestions and bug reports are greatly appreciated:
|
Suggestions and bug reports are greatly appreciated:
|
||||||
|
|
||||||
https://github.com/jkbrzt/httpie/issues
|
https://github.com/jakubroztocil/httpie/issues
|
||||||
|
|
||||||
"""),
|
"""),
|
||||||
)
|
)
|
||||||
@ -209,18 +212,21 @@ output_processing.add_argument(
|
|||||||
help="""
|
help="""
|
||||||
Output coloring style (default is "{default}"). One of:
|
Output coloring style (default is "{default}"). One of:
|
||||||
|
|
||||||
{available}
|
{available_styles}
|
||||||
|
|
||||||
For this option to work properly, please make sure that the $TERM
|
The "{auto_style}" style follows your terminal's ANSI color styles.
|
||||||
environment variable is set to "xterm-256color" or similar
|
|
||||||
|
For non-{auto_style} styles to work properly, please make sure that the
|
||||||
|
$TERM environment variable is set to "xterm-256color" or similar
|
||||||
(e.g., via `export TERM=xterm-256color' in your ~/.bashrc).
|
(e.g., via `export TERM=xterm-256color' in your ~/.bashrc).
|
||||||
|
|
||||||
""".format(
|
""".format(
|
||||||
default=DEFAULT_STYLE,
|
default=DEFAULT_STYLE,
|
||||||
available='\n'.join(
|
available_styles='\n'.join(
|
||||||
'{0}{1}'.format(8 * ' ', line.strip())
|
'{0}{1}'.format(8 * ' ', line.strip())
|
||||||
for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60)
|
for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60)
|
||||||
).rstrip(),
|
).rstrip(),
|
||||||
|
auto_style=AUTO_STYLE,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -544,10 +550,10 @@ ssl.add_argument(
|
|||||||
'--verify',
|
'--verify',
|
||||||
default='yes',
|
default='yes',
|
||||||
help="""
|
help="""
|
||||||
Set to "no" to skip checking the host's SSL certificate. You can also pass
|
Set to "no" (or "false") to skip checking the host's SSL certificate.
|
||||||
the path to a CA_BUNDLE file for private certs. You can also set the
|
Defaults to "yes" ("true"). You can also pass the path to a CA_BUNDLE file
|
||||||
REQUESTS_CA_BUNDLE environment variable. Defaults to "yes".
|
for private certs. (Or you can set the REQUESTS_CA_BUNDLE environment
|
||||||
|
variable instead.)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
ssl.add_argument(
|
ssl.add_argument(
|
||||||
|
@ -3,7 +3,7 @@ import sys
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
from requests.adapters import HTTPAdapter
|
from requests.adapters import HTTPAdapter
|
||||||
from requests.packages import urllib3
|
from requests.structures import CaseInsensitiveDict
|
||||||
|
|
||||||
from httpie import sessions
|
from httpie import sessions
|
||||||
from httpie import __version__
|
from httpie import __version__
|
||||||
@ -14,8 +14,10 @@ from httpie.utils import repr_dict_nice
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# https://urllib3.readthedocs.io/en/latest/security.html
|
# https://urllib3.readthedocs.io/en/latest/security.html
|
||||||
|
# noinspection PyPackageRequirements
|
||||||
|
import urllib3
|
||||||
urllib3.disable_warnings()
|
urllib3.disable_warnings()
|
||||||
except AttributeError:
|
except (ImportError, AttributeError):
|
||||||
# In some rare cases, the user may have an old version of the requests
|
# 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
|
# or urllib3, and there is no method called "disable_warnings." In these
|
||||||
# cases, we don't need to call the method.
|
# cases, we don't need to call the method.
|
||||||
@ -97,7 +99,7 @@ def finalize_headers(headers):
|
|||||||
value = value.strip()
|
value = value.strip()
|
||||||
|
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
# See: https://github.com/jkbrzt/httpie/issues/212
|
# See: https://github.com/jakubroztocil/httpie/issues/212
|
||||||
value = value.encode('utf8')
|
value = value.encode('utf8')
|
||||||
|
|
||||||
final_headers[name] = value
|
final_headers[name] = value
|
||||||
@ -105,9 +107,9 @@ def finalize_headers(headers):
|
|||||||
|
|
||||||
|
|
||||||
def get_default_headers(args):
|
def get_default_headers(args):
|
||||||
default_headers = {
|
default_headers = CaseInsensitiveDict({
|
||||||
'User-Agent': DEFAULT_UA
|
'User-Agent': DEFAULT_UA
|
||||||
}
|
})
|
||||||
|
|
||||||
auto_json = args.data and not args.form
|
auto_json = args.data and not args.form
|
||||||
if args.json or auto_json:
|
if args.json or auto_json:
|
||||||
@ -159,12 +161,14 @@ def get_requests_kwargs(args, base_headers=None):
|
|||||||
'data': data,
|
'data': data,
|
||||||
'verify': {
|
'verify': {
|
||||||
'yes': True,
|
'yes': True,
|
||||||
'no': False
|
'true': True,
|
||||||
}.get(args.verify, args.verify),
|
'no': False,
|
||||||
|
'false': False,
|
||||||
|
}.get(args.verify.lower(), args.verify),
|
||||||
'cert': cert,
|
'cert': cert,
|
||||||
'timeout': args.timeout,
|
'timeout': args.timeout,
|
||||||
'auth': args.auth,
|
'auth': args.auth,
|
||||||
'proxies': dict((p.key, p.value) for p in args.proxy),
|
'proxies': {p.key: p.value for p in args.proxy},
|
||||||
'files': args.files,
|
'files': args.files,
|
||||||
'allow_redirects': args.follow,
|
'allow_redirects': args.follow,
|
||||||
'params': args.params,
|
'params': args.params,
|
||||||
|
141
httpie/compat.py
141
httpie/compat.py
@ -1,12 +1,11 @@
|
|||||||
"""
|
"""
|
||||||
Python 2.6, 2.7, and 3.x compatibility.
|
Python 2.7, and 3.x compatibility.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
is_py2 = sys.version_info[0] == 2
|
is_py2 = sys.version_info[0] == 2
|
||||||
is_py26 = sys.version_info[:2] == (2, 6)
|
|
||||||
is_py27 = sys.version_info[:2] == (2, 7)
|
is_py27 = sys.version_info[:2] == (2, 7)
|
||||||
is_py3 = sys.version_info[0] == 3
|
is_py3 = sys.version_info[0] == 3
|
||||||
is_pypy = 'pypy' in sys.version.lower()
|
is_pypy = 'pypy' in sys.version.lower()
|
||||||
@ -38,141 +37,3 @@ try: # pragma: no cover
|
|||||||
except ImportError: # pragma: no cover
|
except ImportError: # pragma: no cover
|
||||||
# noinspection PyCompatibility,PyUnresolvedReferences
|
# noinspection PyCompatibility,PyUnresolvedReferences
|
||||||
from urllib2 import urlopen
|
from urllib2 import urlopen
|
||||||
|
|
||||||
try: # pragma: no cover
|
|
||||||
from collections import OrderedDict
|
|
||||||
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,PyUnresolvedReferences
|
|
||||||
from UserDict import DictMixin
|
|
||||||
|
|
||||||
# noinspection PyShadowingBuiltins,PyCompatibility
|
|
||||||
class OrderedDict(dict, DictMixin):
|
|
||||||
# Copyright (c) 2009 Raymond Hettinger
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person
|
|
||||||
# obtaining a copy of this software and associated documentation files
|
|
||||||
# (the "Software"), to deal in the Software without restriction,
|
|
||||||
# including without limitation the rights to use, copy, modify, merge,
|
|
||||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
# and to permit persons to whom the Software is furnished to do so,
|
|
||||||
# subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be
|
|
||||||
# included in all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
# noinspection PyMissingConstructor
|
|
||||||
def __init__(self, *args, **kwds):
|
|
||||||
if len(args) > 1:
|
|
||||||
raise TypeError('expected at most 1 arguments, got %d'
|
|
||||||
% len(args))
|
|
||||||
try:
|
|
||||||
self.__end
|
|
||||||
except AttributeError:
|
|
||||||
self.clear()
|
|
||||||
self.update(*args, **kwds)
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self.__end = end = []
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
end += [None, end, end] # sentinel node for doubly linked list
|
|
||||||
self.__map = {} # key --> [key, prev, next]
|
|
||||||
dict.clear(self)
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
if key not in self:
|
|
||||||
end = self.__end
|
|
||||||
curr = end[1]
|
|
||||||
curr[2] = end[1] = self.__map[key] = [key, curr, end]
|
|
||||||
dict.__setitem__(self, key, value)
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
|
||||||
dict.__delitem__(self, key)
|
|
||||||
key, prev, next = self.__map.pop(key)
|
|
||||||
prev[2] = next
|
|
||||||
next[1] = prev
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
end = self.__end
|
|
||||||
curr = end[2]
|
|
||||||
while curr is not end:
|
|
||||||
yield curr[0]
|
|
||||||
curr = curr[2]
|
|
||||||
|
|
||||||
def __reversed__(self):
|
|
||||||
end = self.__end
|
|
||||||
curr = end[1]
|
|
||||||
while curr is not end:
|
|
||||||
yield curr[0]
|
|
||||||
curr = curr[1]
|
|
||||||
|
|
||||||
def popitem(self, last=True):
|
|
||||||
if not self:
|
|
||||||
raise KeyError('dictionary is empty')
|
|
||||||
if last:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
key = reversed(self).next()
|
|
||||||
else:
|
|
||||||
key = iter(self).next()
|
|
||||||
value = self.pop(key)
|
|
||||||
return key, value
|
|
||||||
|
|
||||||
def __reduce__(self):
|
|
||||||
items = [[k, self[k]] for k in self]
|
|
||||||
tmp = self.__map, self.__end
|
|
||||||
del self.__map, self.__end
|
|
||||||
inst_dict = vars(self).copy()
|
|
||||||
self.__map, self.__end = tmp
|
|
||||||
if inst_dict:
|
|
||||||
return self.__class__, (items,), inst_dict
|
|
||||||
return self.__class__, (items,)
|
|
||||||
|
|
||||||
def keys(self):
|
|
||||||
return list(self)
|
|
||||||
|
|
||||||
setdefault = DictMixin.setdefault
|
|
||||||
update = DictMixin.update
|
|
||||||
pop = DictMixin.pop
|
|
||||||
values = DictMixin.values
|
|
||||||
items = DictMixin.items
|
|
||||||
iterkeys = DictMixin.iterkeys
|
|
||||||
itervalues = DictMixin.itervalues
|
|
||||||
iteritems = DictMixin.iteritems
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
if not self:
|
|
||||||
return '%s()' % (self.__class__.__name__,)
|
|
||||||
return '%s(%r)' % (self.__class__.__name__, self.items())
|
|
||||||
|
|
||||||
def copy(self):
|
|
||||||
return self.__class__(self)
|
|
||||||
|
|
||||||
# noinspection PyMethodOverriding
|
|
||||||
@classmethod
|
|
||||||
def fromkeys(cls, iterable, value=None):
|
|
||||||
d = cls()
|
|
||||||
for key in iterable:
|
|
||||||
d[key] = value
|
|
||||||
return d
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
if isinstance(other, OrderedDict):
|
|
||||||
if len(self) != len(other):
|
|
||||||
return False
|
|
||||||
for p, q in zip(self.items(), other.items()):
|
|
||||||
if p != q:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
return dict.__eq__(self, other)
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
return not self == other
|
|
||||||
|
@ -80,7 +80,7 @@ class BaseConfigDict(dict):
|
|||||||
class Config(BaseConfigDict):
|
class Config(BaseConfigDict):
|
||||||
|
|
||||||
name = 'config'
|
name = 'config'
|
||||||
helpurl = 'https://httpie.org/docs#config'
|
helpurl = 'https://httpie.org/doc#config'
|
||||||
about = 'HTTPie configuration file'
|
about = 'HTTPie configuration file'
|
||||||
|
|
||||||
DEFAULTS = {
|
DEFAULTS = {
|
||||||
@ -104,7 +104,7 @@ class Config(BaseConfigDict):
|
|||||||
try:
|
try:
|
||||||
implicit_content_type = self.pop('implicit_content_type')
|
implicit_content_type = self.pop('implicit_content_type')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
self.save()
|
||||||
else:
|
else:
|
||||||
if implicit_content_type == 'form':
|
if implicit_content_type == 'form':
|
||||||
self['default_options'].insert(0, '--form')
|
self['default_options'].insert(0, '--form')
|
||||||
|
@ -43,7 +43,7 @@ def get_exit_status(http_status, follow=False):
|
|||||||
# Server Error
|
# Server Error
|
||||||
return ExitStatus.ERROR_HTTP_5XX
|
return ExitStatus.ERROR_HTTP_5XX
|
||||||
else:
|
else:
|
||||||
return ExitStatus.OK
|
return ExitStatus.SUCCESS
|
||||||
|
|
||||||
|
|
||||||
def print_debug_info(env):
|
def print_debug_info(env):
|
||||||
@ -61,7 +61,7 @@ def print_debug_info(env):
|
|||||||
|
|
||||||
def decode_args(args, stdin_encoding):
|
def decode_args(args, stdin_encoding):
|
||||||
"""
|
"""
|
||||||
Convert all bytes ags to str
|
Convert all bytes args to str
|
||||||
by decoding them using stdin encoding.
|
by decoding them using stdin encoding.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -82,7 +82,7 @@ def program(args, env, log_error):
|
|||||||
:return: status code
|
:return: status code
|
||||||
|
|
||||||
"""
|
"""
|
||||||
exit_status = ExitStatus.OK
|
exit_status = ExitStatus.SUCCESS
|
||||||
downloader = None
|
downloader = None
|
||||||
show_traceback = args.debug or args.traceback
|
show_traceback = args.debug or args.traceback
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ def program(args, env, log_error):
|
|||||||
http_status=response.status_code,
|
http_status=response.status_code,
|
||||||
follow=args.follow
|
follow=args.follow
|
||||||
)
|
)
|
||||||
if not env.stdout_isatty and exit_status != ExitStatus.OK:
|
if not env.stdout_isatty and exit_status != ExitStatus.SUCCESS:
|
||||||
log_error(
|
log_error(
|
||||||
'HTTP %s %s', response.raw.status, response.raw.reason,
|
'HTTP %s %s', response.raw.status, response.raw.reason,
|
||||||
level='warning'
|
level='warning'
|
||||||
@ -143,7 +143,7 @@ def program(args, env, log_error):
|
|||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if downloader and exit_status == ExitStatus.OK:
|
if downloader and exit_status == ExitStatus.SUCCESS:
|
||||||
# Last response body download.
|
# Last response body download.
|
||||||
download_stream, download_to = downloader.start(final_response)
|
download_stream, download_to = downloader.start(final_response)
|
||||||
write_stream(
|
write_stream(
|
||||||
@ -164,8 +164,8 @@ def program(args, env, log_error):
|
|||||||
if downloader and not downloader.finished:
|
if downloader and not downloader.finished:
|
||||||
downloader.failed()
|
downloader.failed()
|
||||||
|
|
||||||
if (not isinstance(args, list) and args.output_file and
|
if (not isinstance(args, list) and args.output_file
|
||||||
args.output_file_specified):
|
and args.output_file_specified):
|
||||||
args.output_file.close()
|
args.output_file.close()
|
||||||
|
|
||||||
|
|
||||||
@ -202,9 +202,9 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None):
|
|||||||
if include_debug_info:
|
if include_debug_info:
|
||||||
print_debug_info(env)
|
print_debug_info(env)
|
||||||
if args == ['--debug']:
|
if args == ['--debug']:
|
||||||
return ExitStatus.OK
|
return ExitStatus.SUCCESS
|
||||||
|
|
||||||
exit_status = ExitStatus.OK
|
exit_status = ExitStatus.SUCCESS
|
||||||
|
|
||||||
try:
|
try:
|
||||||
parsed_args = parser.parse_args(args=args, env=env)
|
parsed_args = parser.parse_args(args=args, env=env)
|
||||||
@ -214,7 +214,7 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None):
|
|||||||
raise
|
raise
|
||||||
exit_status = ExitStatus.ERROR_CTRL_C
|
exit_status = ExitStatus.ERROR_CTRL_C
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
if e.code != ExitStatus.OK:
|
if e.code != ExitStatus.SUCCESS:
|
||||||
env.stderr.write('\n')
|
env.stderr.write('\n')
|
||||||
if include_traceback:
|
if include_traceback:
|
||||||
raise
|
raise
|
||||||
@ -232,7 +232,7 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None):
|
|||||||
raise
|
raise
|
||||||
exit_status = ExitStatus.ERROR_CTRL_C
|
exit_status = ExitStatus.ERROR_CTRL_C
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
if e.code != ExitStatus.OK:
|
if e.code != ExitStatus.SUCCESS:
|
||||||
env.stderr.write('\n')
|
env.stderr.write('\n')
|
||||||
if include_traceback:
|
if include_traceback:
|
||||||
raise
|
raise
|
||||||
|
@ -54,8 +54,8 @@ def parse_content_range(content_range, resumed_from):
|
|||||||
raise ContentRangeError('Missing Content-Range')
|
raise ContentRangeError('Missing Content-Range')
|
||||||
|
|
||||||
pattern = (
|
pattern = (
|
||||||
'^bytes (?P<first_byte_pos>\d+)-(?P<last_byte_pos>\d+)'
|
r'^bytes (?P<first_byte_pos>\d+)-(?P<last_byte_pos>\d+)'
|
||||||
'/(\*|(?P<instance_length>\d+))$'
|
r'/(\*|(?P<instance_length>\d+))$'
|
||||||
)
|
)
|
||||||
match = re.match(pattern, content_range)
|
match = re.match(pattern, content_range)
|
||||||
|
|
||||||
@ -78,15 +78,15 @@ def parse_content_range(content_range, resumed_from):
|
|||||||
# last-byte-pos value, is invalid. The recipient of an invalid
|
# last-byte-pos value, is invalid. The recipient of an invalid
|
||||||
# byte-content-range- spec MUST ignore it and any content
|
# byte-content-range- spec MUST ignore it and any content
|
||||||
# transferred along with it."
|
# transferred along with it."
|
||||||
if (first_byte_pos >= last_byte_pos or
|
if (first_byte_pos >= last_byte_pos
|
||||||
(instance_length is not None and
|
or (instance_length is not None
|
||||||
instance_length <= last_byte_pos)):
|
and instance_length <= last_byte_pos)):
|
||||||
raise ContentRangeError(
|
raise ContentRangeError(
|
||||||
'Invalid Content-Range returned: %r' % content_range)
|
'Invalid Content-Range returned: %r' % content_range)
|
||||||
|
|
||||||
if (first_byte_pos != resumed_from or
|
if (first_byte_pos != resumed_from
|
||||||
(instance_length is not None and
|
or (instance_length is not None
|
||||||
last_byte_pos + 1 != instance_length)):
|
and last_byte_pos + 1 != instance_length)):
|
||||||
# Not what we asked for.
|
# Not what we asked for.
|
||||||
raise ContentRangeError(
|
raise ContentRangeError(
|
||||||
'Unexpected Content-Range returned (%r)'
|
'Unexpected Content-Range returned (%r)'
|
||||||
@ -105,7 +105,7 @@ def filename_from_content_disposition(content_disposition):
|
|||||||
:return: the filename if present and valid, otherwise `None`
|
:return: the filename if present and valid, otherwise `None`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# attachment; filename=jkbrzt-httpie-0.4.1-20-g40bd8f6.tar.gz
|
# attachment; filename=jakubroztocil-httpie-0.4.1-20-g40bd8f6.tar.gz
|
||||||
|
|
||||||
msg = Message('Content-Disposition: %s' % content_disposition)
|
msg = Message('Content-Disposition: %s' % content_disposition)
|
||||||
filename = msg.get_filename()
|
filename = msg.get_filename()
|
||||||
@ -238,7 +238,7 @@ class Downloader(object):
|
|||||||
assert not self.status.time_started
|
assert not self.status.time_started
|
||||||
|
|
||||||
# FIXME: some servers still might sent Content-Encoding: gzip
|
# FIXME: some servers still might sent Content-Encoding: gzip
|
||||||
# <https://github.com/jkbrzt/httpie/issues/423>
|
# <https://github.com/jakubroztocil/httpie/issues/423>
|
||||||
try:
|
try:
|
||||||
total_size = int(response.headers['Content-Length'])
|
total_size = int(response.headers['Content-Length'])
|
||||||
except (KeyError, ValueError, TypeError):
|
except (KeyError, ValueError, TypeError):
|
||||||
@ -308,9 +308,9 @@ class Downloader(object):
|
|||||||
@property
|
@property
|
||||||
def interrupted(self):
|
def interrupted(self):
|
||||||
return (
|
return (
|
||||||
self.finished and
|
self.finished
|
||||||
self.status.total_size and
|
and self.status.total_size
|
||||||
self.status.total_size != self.status.downloaded
|
and self.status.total_size != self.status.downloaded
|
||||||
)
|
)
|
||||||
|
|
||||||
def chunk_downloaded(self, chunk):
|
def chunk_downloaded(self, chunk):
|
||||||
@ -399,8 +399,8 @@ class ProgressReporterThread(threading.Thread):
|
|||||||
if now - self._prev_time >= self._update_interval:
|
if now - self._prev_time >= self._update_interval:
|
||||||
downloaded = self.status.downloaded
|
downloaded = self.status.downloaded
|
||||||
try:
|
try:
|
||||||
speed = ((downloaded - self._prev_bytes) /
|
speed = ((downloaded - self._prev_bytes)
|
||||||
(now - self._prev_time))
|
/ (now - self._prev_time))
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
speed = 0
|
speed = 0
|
||||||
|
|
||||||
@ -434,11 +434,11 @@ class ProgressReporterThread(threading.Thread):
|
|||||||
self._prev_bytes = downloaded
|
self._prev_bytes = downloaded
|
||||||
|
|
||||||
self.output.write(
|
self.output.write(
|
||||||
CLEAR_LINE +
|
CLEAR_LINE
|
||||||
' ' +
|
+ ' '
|
||||||
SPINNER[self._spinner_pos] +
|
+ SPINNER[self._spinner_pos]
|
||||||
' ' +
|
+ ' '
|
||||||
self._status_line
|
+ self._status_line
|
||||||
)
|
)
|
||||||
self.output.flush()
|
self.output.flush()
|
||||||
|
|
||||||
@ -463,8 +463,8 @@ class ProgressReporterThread(threading.Thread):
|
|||||||
|
|
||||||
self.output.write(SUMMARY.format(
|
self.output.write(SUMMARY.format(
|
||||||
downloaded=humanize_bytes(actually_downloaded),
|
downloaded=humanize_bytes(actually_downloaded),
|
||||||
total=(self.status.total_size and
|
total=(self.status.total_size
|
||||||
humanize_bytes(self.status.total_size)),
|
and humanize_bytes(self.status.total_size)),
|
||||||
speed=humanize_bytes(speed),
|
speed=humanize_bytes(speed),
|
||||||
time=time_taken,
|
time=time_taken,
|
||||||
))
|
))
|
||||||
|
@ -9,16 +9,16 @@ import errno
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import getpass
|
import getpass
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from collections import namedtuple, Iterable
|
from collections import namedtuple, Iterable, OrderedDict
|
||||||
# noinspection PyCompatibility
|
# noinspection PyCompatibility
|
||||||
from argparse import ArgumentParser, ArgumentTypeError, ArgumentError
|
from argparse import ArgumentParser, ArgumentTypeError, ArgumentError
|
||||||
|
|
||||||
# TODO: Use MultiDict for headers once added to `requests`.
|
# TODO: Use MultiDict for headers once added to `requests`.
|
||||||
# https://github.com/jkbrzt/httpie/issues/130
|
# https://github.com/jakubroztocil/httpie/issues/130
|
||||||
from httpie.plugins import plugin_manager
|
from httpie.plugins import plugin_manager
|
||||||
from requests.structures import CaseInsensitiveDict
|
from requests.structures import CaseInsensitiveDict
|
||||||
|
|
||||||
from httpie.compat import OrderedDict, urlsplit, str, is_pypy, is_py27
|
from httpie.compat import urlsplit, str, is_pypy, is_py27
|
||||||
from httpie.sessions import VALID_SESSION_NAME_PATTERN
|
from httpie.sessions import VALID_SESSION_NAME_PATTERN
|
||||||
from httpie.utils import load_json_preserve_order
|
from httpie.utils import load_json_preserve_order
|
||||||
|
|
||||||
@ -111,12 +111,13 @@ SSL_VERSION_ARG_MAPPING = {
|
|||||||
'tls1': 'PROTOCOL_TLSv1',
|
'tls1': 'PROTOCOL_TLSv1',
|
||||||
'tls1.1': 'PROTOCOL_TLSv1_1',
|
'tls1.1': 'PROTOCOL_TLSv1_1',
|
||||||
'tls1.2': 'PROTOCOL_TLSv1_2',
|
'tls1.2': 'PROTOCOL_TLSv1_2',
|
||||||
|
'tls1.3': 'PROTOCOL_TLSv1_3',
|
||||||
}
|
}
|
||||||
SSL_VERSION_ARG_MAPPING = dict(
|
SSL_VERSION_ARG_MAPPING = {
|
||||||
(cli_arg, getattr(ssl, ssl_constant))
|
cli_arg: getattr(ssl, ssl_constant)
|
||||||
for cli_arg, ssl_constant in SSL_VERSION_ARG_MAPPING.items()
|
for cli_arg, ssl_constant in SSL_VERSION_ARG_MAPPING.items()
|
||||||
if hasattr(ssl, ssl_constant)
|
if hasattr(ssl, ssl_constant)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
|
||||||
class HTTPieArgumentParser(ArgumentParser):
|
class HTTPieArgumentParser(ArgumentParser):
|
||||||
@ -254,8 +255,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
|||||||
else:
|
else:
|
||||||
credentials = parse_auth(self.args.auth)
|
credentials = parse_auth(self.args.auth)
|
||||||
|
|
||||||
if (not credentials.has_password() and
|
if (not credentials.has_password()
|
||||||
plugin.prompt_password):
|
and plugin.prompt_password):
|
||||||
if self.args.ignore_stdin:
|
if self.args.ignore_stdin:
|
||||||
# Non-tty stdin read by now
|
# Non-tty stdin read by now
|
||||||
self.error(
|
self.error(
|
||||||
@ -302,7 +303,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
|||||||
"""
|
"""
|
||||||
if self.args.data:
|
if self.args.data:
|
||||||
self.error('Request body (from stdin or a file) and request '
|
self.error('Request body (from stdin or a file) and request '
|
||||||
'data (key=value) cannot be mixed.')
|
'data (key=value) cannot be mixed. Pass '
|
||||||
|
'--ignore-stdin to let key/value take priority.')
|
||||||
self.args.data = getattr(fd, 'buffer', fd).read()
|
self.args.data = getattr(fd, 'buffer', fd).read()
|
||||||
|
|
||||||
def _guess_method(self):
|
def _guess_method(self):
|
||||||
@ -337,10 +339,11 @@ class HTTPieArgumentParser(ArgumentParser):
|
|||||||
self.args.url = self.args.method
|
self.args.url = self.args.method
|
||||||
# Infer the method
|
# Infer the method
|
||||||
has_data = (
|
has_data = (
|
||||||
(not self.args.ignore_stdin and
|
(not self.args.ignore_stdin and not self.env.stdin_isatty)
|
||||||
not self.env.stdin_isatty) or
|
or any(
|
||||||
any(item.sep in SEP_GROUP_DATA_ITEMS
|
item.sep in SEP_GROUP_DATA_ITEMS
|
||||||
for item in self.args.items)
|
for item in self.args.items
|
||||||
|
)
|
||||||
)
|
)
|
||||||
self.args.method = HTTP_POST if has_data else HTTP_GET
|
self.args.method = HTTP_POST if has_data else HTTP_GET
|
||||||
|
|
||||||
@ -425,8 +428,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
|||||||
if self.args.prettify == PRETTY_STDOUT_TTY_ONLY:
|
if self.args.prettify == PRETTY_STDOUT_TTY_ONLY:
|
||||||
self.args.prettify = PRETTY_MAP[
|
self.args.prettify = PRETTY_MAP[
|
||||||
'all' if self.env.stdout_isatty else 'none']
|
'all' if self.env.stdout_isatty else 'none']
|
||||||
elif (self.args.prettify and self.env.is_windows and
|
elif (self.args.prettify and self.env.is_windows
|
||||||
self.args.output_file):
|
and self.args.output_file):
|
||||||
self.error('Only terminal output can be colorized on Windows.')
|
self.error('Only terminal output can be colorized on Windows.')
|
||||||
else:
|
else:
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
@ -468,8 +471,8 @@ class SessionNameValidator(object):
|
|||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
# Session name can be a path or just a name.
|
# Session name can be a path or just a name.
|
||||||
if (os.path.sep not in value and
|
if (os.path.sep not in value
|
||||||
not VALID_SESSION_NAME_PATTERN.search(value)):
|
and not VALID_SESSION_NAME_PATTERN.search(value)):
|
||||||
raise ArgumentError(None, self.error_message)
|
raise ArgumentError(None, self.error_message)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -504,7 +507,7 @@ class KeyValueArgType(object):
|
|||||||
"""Represents an escaped character."""
|
"""Represents an escaped character."""
|
||||||
|
|
||||||
def tokenize(string):
|
def tokenize(string):
|
||||||
"""Tokenize `string`. There are only two token types - strings
|
r"""Tokenize `string`. There are only two token types - strings
|
||||||
and escaped characters:
|
and escaped characters:
|
||||||
|
|
||||||
tokenize(r'foo\=bar\\baz')
|
tokenize(r'foo\=bar\\baz')
|
||||||
|
@ -9,21 +9,25 @@ import pygments.style
|
|||||||
from pygments.formatters.terminal import TerminalFormatter
|
from pygments.formatters.terminal import TerminalFormatter
|
||||||
from pygments.formatters.terminal256 import Terminal256Formatter
|
from pygments.formatters.terminal256 import Terminal256Formatter
|
||||||
from pygments.lexers.special import TextLexer
|
from pygments.lexers.special import TextLexer
|
||||||
|
from pygments.lexers.text import HttpLexer as PygmentsHttpLexer
|
||||||
from pygments.util import ClassNotFound
|
from pygments.util import ClassNotFound
|
||||||
|
|
||||||
from httpie.compat import is_windows
|
from httpie.compat import is_windows
|
||||||
from httpie.plugins import FormatterPlugin
|
from httpie.plugins import FormatterPlugin
|
||||||
|
|
||||||
|
|
||||||
AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys())
|
AUTO_STYLE = 'auto' # Follows terminal ANSI color styles
|
||||||
AVAILABLE_STYLES.add('solarized')
|
DEFAULT_STYLE = AUTO_STYLE
|
||||||
|
SOLARIZED_STYLE = 'solarized' # Bundled here
|
||||||
if is_windows:
|
if is_windows:
|
||||||
# Colors on Windows via colorama don't look that
|
# Colors on Windows via colorama don't look that
|
||||||
# great and fruity seems to give the best result there
|
# great and fruity seems to give the best result there.
|
||||||
DEFAULT_STYLE = 'fruity'
|
DEFAULT_STYLE = 'fruity'
|
||||||
else:
|
|
||||||
DEFAULT_STYLE = 'solarized'
|
|
||||||
|
AVAILABLE_STYLES = set(pygments.styles.get_all_styles())
|
||||||
|
AVAILABLE_STYLES.add(SOLARIZED_STYLE)
|
||||||
|
AVAILABLE_STYLES.add(AUTO_STYLE)
|
||||||
|
|
||||||
|
|
||||||
class ColorFormatter(FormatterPlugin):
|
class ColorFormatter(FormatterPlugin):
|
||||||
@ -39,40 +43,56 @@ class ColorFormatter(FormatterPlugin):
|
|||||||
def __init__(self, env, explicit_json=False,
|
def __init__(self, env, explicit_json=False,
|
||||||
color_scheme=DEFAULT_STYLE, **kwargs):
|
color_scheme=DEFAULT_STYLE, **kwargs):
|
||||||
super(ColorFormatter, self).__init__(**kwargs)
|
super(ColorFormatter, self).__init__(**kwargs)
|
||||||
|
|
||||||
if not env.colors:
|
if not env.colors:
|
||||||
self.enabled = False
|
self.enabled = False
|
||||||
return
|
return
|
||||||
|
|
||||||
# --json, -j
|
use_auto_style = color_scheme == AUTO_STYLE
|
||||||
self.explicit_json = explicit_json
|
has_256_colors = env.colors == 256
|
||||||
|
if use_auto_style or not has_256_colors:
|
||||||
try:
|
http_lexer = PygmentsHttpLexer()
|
||||||
style_class = pygments.styles.get_style_by_name(color_scheme)
|
formatter = TerminalFormatter()
|
||||||
except ClassNotFound:
|
|
||||||
style_class = Solarized256Style
|
|
||||||
|
|
||||||
if env.colors == 256:
|
|
||||||
fmt_class = Terminal256Formatter
|
|
||||||
else:
|
else:
|
||||||
fmt_class = TerminalFormatter
|
http_lexer = SimplifiedHTTPLexer()
|
||||||
self.formatter = fmt_class(style=style_class)
|
formatter = Terminal256Formatter(
|
||||||
|
style=self.get_style_class(color_scheme)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.explicit_json = explicit_json # --json
|
||||||
|
self.formatter = formatter
|
||||||
|
self.http_lexer = http_lexer
|
||||||
|
|
||||||
def format_headers(self, headers):
|
def format_headers(self, headers):
|
||||||
return pygments.highlight(headers, HTTPLexer(), self.formatter).strip()
|
return pygments.highlight(
|
||||||
|
code=headers,
|
||||||
|
lexer=self.http_lexer,
|
||||||
|
formatter=self.formatter,
|
||||||
|
).strip()
|
||||||
|
|
||||||
def format_body(self, body, mime):
|
def format_body(self, body, mime):
|
||||||
lexer = self.get_lexer(mime, body)
|
lexer = self.get_lexer_for_body(mime, body)
|
||||||
if lexer:
|
if lexer:
|
||||||
body = pygments.highlight(body, lexer, self.formatter)
|
body = pygments.highlight(
|
||||||
|
code=body,
|
||||||
|
lexer=lexer,
|
||||||
|
formatter=self.formatter,
|
||||||
|
)
|
||||||
return body.strip()
|
return body.strip()
|
||||||
|
|
||||||
def get_lexer(self, mime, body):
|
def get_lexer_for_body(self, mime, body):
|
||||||
return get_lexer(
|
return get_lexer(
|
||||||
mime=mime,
|
mime=mime,
|
||||||
explicit_json=self.explicit_json,
|
explicit_json=self.explicit_json,
|
||||||
body=body,
|
body=body,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_style_class(self, color_scheme):
|
||||||
|
try:
|
||||||
|
return pygments.styles.get_style_by_name(color_scheme)
|
||||||
|
except ClassNotFound:
|
||||||
|
return Solarized256Style
|
||||||
|
|
||||||
|
|
||||||
def get_lexer(mime, explicit_json=False, body=''):
|
def get_lexer(mime, explicit_json=False, body=''):
|
||||||
|
|
||||||
@ -121,7 +141,7 @@ def get_lexer(mime, explicit_json=False, body=''):
|
|||||||
return lexer
|
return lexer
|
||||||
|
|
||||||
|
|
||||||
class HTTPLexer(pygments.lexer.RegexLexer):
|
class SimplifiedHTTPLexer(pygments.lexer.RegexLexer):
|
||||||
"""Simplified HTTP lexer for Pygments.
|
"""Simplified HTTP lexer for Pygments.
|
||||||
|
|
||||||
It only operates on headers and provides a stronger contrast between
|
It only operates on headers and provides a stronger contrast between
|
||||||
|
@ -15,8 +15,8 @@ class JSONFormatter(FormatterPlugin):
|
|||||||
'javascript',
|
'javascript',
|
||||||
'text',
|
'text',
|
||||||
]
|
]
|
||||||
if (self.kwargs['explicit_json'] or
|
if (self.kwargs['explicit_json']
|
||||||
any(token in mime for token in maybe_json)):
|
or any(token in mime for token in maybe_json)):
|
||||||
try:
|
try:
|
||||||
obj = json.loads(body)
|
obj = json.loads(body)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -15,7 +15,7 @@ class AuthPlugin(BasePlugin):
|
|||||||
"""
|
"""
|
||||||
Base auth plugin class.
|
Base auth plugin class.
|
||||||
|
|
||||||
See <https://github.com/jkbrzt/httpie-ntlm> for an example auth plugin.
|
See <https://github.com/httpie/httpie-ntlm> for an example auth plugin.
|
||||||
|
|
||||||
See also `test_auth_plugins.py`
|
See also `test_auth_plugins.py`
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class HTTPBasicAuth(requests.auth.HTTPBasicAuth):
|
|||||||
"""
|
"""
|
||||||
Override username/password serialization to allow unicode.
|
Override username/password serialization to allow unicode.
|
||||||
|
|
||||||
See https://github.com/jkbrzt/httpie/issues/212
|
See https://github.com/jakubroztocil/httpie/issues/212
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r.headers['Authorization'] = type(self).make_header(
|
r.headers['Authorization'] = type(self).make_header(
|
||||||
|
@ -39,8 +39,7 @@ class PluginManager(object):
|
|||||||
return [plugin for plugin in self if issubclass(plugin, AuthPlugin)]
|
return [plugin for plugin in self if issubclass(plugin, AuthPlugin)]
|
||||||
|
|
||||||
def get_auth_plugin_mapping(self):
|
def get_auth_plugin_mapping(self):
|
||||||
return dict((plugin.auth_type, plugin)
|
return {plugin.auth_type: plugin for plugin in self.get_auth_plugins()}
|
||||||
for plugin in self.get_auth_plugins())
|
|
||||||
|
|
||||||
def get_auth_plugin(self, auth_type):
|
def get_auth_plugin(self, auth_type):
|
||||||
return self.get_auth_plugin_mapping()[auth_type]
|
return self.get_auth_plugin_mapping()[auth_type]
|
||||||
|
@ -30,8 +30,8 @@ def get_response(requests_session, session_name,
|
|||||||
if os.path.sep in session_name:
|
if os.path.sep in session_name:
|
||||||
path = os.path.expanduser(session_name)
|
path = os.path.expanduser(session_name)
|
||||||
else:
|
else:
|
||||||
hostname = (args.headers.get('Host', None) or
|
hostname = (args.headers.get('Host', None)
|
||||||
urlsplit(args.url).netloc.split('@')[-1])
|
or urlsplit(args.url).netloc.split('@')[-1])
|
||||||
if not hostname:
|
if not hostname:
|
||||||
# HACK/FIXME: httpie-unixsocket's URLs have no hostname.
|
# HACK/FIXME: httpie-unixsocket's URLs have no hostname.
|
||||||
hostname = 'localhost'
|
hostname = 'localhost'
|
||||||
@ -74,7 +74,7 @@ def get_response(requests_session, session_name,
|
|||||||
|
|
||||||
|
|
||||||
class Session(BaseConfigDict):
|
class Session(BaseConfigDict):
|
||||||
helpurl = 'https://httpie.org/docs#sessions'
|
helpurl = 'https://httpie.org/doc#sessions'
|
||||||
about = 'HTTPie session file'
|
about = 'HTTPie session file'
|
||||||
|
|
||||||
def __init__(self, path, *args, **kwargs):
|
def __init__(self, path, *args, **kwargs):
|
||||||
@ -136,10 +136,10 @@ class Session(BaseConfigDict):
|
|||||||
stored_attrs = ['value', 'path', 'secure', 'expires']
|
stored_attrs = ['value', 'path', 'secure', 'expires']
|
||||||
self['cookies'] = {}
|
self['cookies'] = {}
|
||||||
for cookie in jar:
|
for cookie in jar:
|
||||||
self['cookies'][cookie.name] = dict(
|
self['cookies'][cookie.name] = {
|
||||||
(attname, getattr(cookie, attname))
|
attname: getattr(cookie, attname)
|
||||||
for attname in stored_attrs
|
for attname in stored_attrs
|
||||||
)
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def auth(self):
|
def auth(self):
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
from __future__ import division
|
from __future__ import division
|
||||||
import json
|
import json
|
||||||
|
from collections import OrderedDict
|
||||||
from httpie.compat import is_py26, OrderedDict
|
|
||||||
|
|
||||||
|
|
||||||
def load_json_preserve_order(s):
|
def load_json_preserve_order(s):
|
||||||
if is_py26:
|
|
||||||
return json.loads(s)
|
|
||||||
return json.loads(s, object_pairs_hook=OrderedDict)
|
return json.loads(s, object_pairs_hook=OrderedDict)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
[pytest]
|
|
||||||
norecursedirs = tests/fixtures
|
|
@ -5,3 +5,4 @@ pytest-cov
|
|||||||
pytest-httpbin>=0.0.6
|
pytest-httpbin>=0.0.6
|
||||||
docutils
|
docutils
|
||||||
wheel
|
wheel
|
||||||
|
pycodestyle
|
||||||
|
17
setup.cfg
17
setup.cfg
@ -1,2 +1,19 @@
|
|||||||
[wheel]
|
[wheel]
|
||||||
universal = 1
|
universal = 1
|
||||||
|
|
||||||
|
|
||||||
|
[tool:pytest]
|
||||||
|
# <https://docs.pytest.org/en/latest/customize.html>
|
||||||
|
norecursedirs = tests/fixtures
|
||||||
|
|
||||||
|
|
||||||
|
[pycodestyle]
|
||||||
|
# <http://pycodestyle.pycqa.org/en/latest/intro.html#configuration>
|
||||||
|
|
||||||
|
exclude = .git,.idea,__pycache__,build,dist,.tox,.pytest_cache,*.egg-info
|
||||||
|
|
||||||
|
# <http://pycodestyle.pycqa.org/en/latest/intro.html#error-codes>
|
||||||
|
# E241 - multiple spaces after ‘,’
|
||||||
|
# E501 - line too long
|
||||||
|
# W503 - line break before binary operator
|
||||||
|
ignore = E241,E501,W503
|
||||||
|
12
setup.py
12
setup.py
@ -35,7 +35,7 @@ tests_require = [
|
|||||||
|
|
||||||
|
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'requests>=2.11.0',
|
'requests>=2.18.4',
|
||||||
'Pygments>=2.1.3'
|
'Pygments>=2.1.3'
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -58,9 +58,7 @@ if 'bdist_wheel' not in sys.argv:
|
|||||||
# bdist_wheel
|
# bdist_wheel
|
||||||
extras_require = {
|
extras_require = {
|
||||||
# http://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies
|
# http://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies
|
||||||
':python_version == "2.6"'
|
'python_version == "3.0" or python_version == "3.1"': ['argparse>=1.2.1'],
|
||||||
' or python_version == "3.0"'
|
|
||||||
' or python_version == "3.1" ': ['argparse>=1.2.1'],
|
|
||||||
':sys_platform == "win32"': ['colorama>=0.2.4'],
|
':sys_platform == "win32"': ['colorama>=0.2.4'],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +74,7 @@ setup(
|
|||||||
description=httpie.__doc__.strip(),
|
description=httpie.__doc__.strip(),
|
||||||
long_description=long_description(),
|
long_description=long_description(),
|
||||||
url='http://httpie.org/',
|
url='http://httpie.org/',
|
||||||
download_url='https://github.com/jkbrzt/httpie',
|
download_url='https://github.com/jakubroztocil/httpie',
|
||||||
author=httpie.__author__,
|
author=httpie.__author__,
|
||||||
author_email='jakub@roztocil.co',
|
author_email='jakub@roztocil.co',
|
||||||
license=httpie.__licence__,
|
license=httpie.__licence__,
|
||||||
@ -93,14 +91,14 @@ setup(
|
|||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 2',
|
|
||||||
'Programming Language :: Python :: 2.6',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.1',
|
'Programming Language :: Python :: 3.1',
|
||||||
'Programming Language :: Python :: 3.2',
|
'Programming Language :: Python :: 3.2',
|
||||||
'Programming Language :: Python :: 3.3',
|
'Programming Language :: Python :: 3.3',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
'Environment :: Console',
|
'Environment :: Console',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'Intended Audience :: System Administrators',
|
'Intended Audience :: System Administrators',
|
||||||
|
@ -5,4 +5,4 @@ HTTPie Test Suite
|
|||||||
Please see `CONTRIBUTING`_.
|
Please see `CONTRIBUTING`_.
|
||||||
|
|
||||||
|
|
||||||
.. _CONTRIBUTING: https://github.com/jkbrzt/httpie/blob/master/CONTRIBUTING.rst
|
.. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from pytest_httpbin.plugin import httpbin_ca_bundle
|
from pytest_httpbin import certs
|
||||||
|
|
||||||
|
|
||||||
# Make httpbin's CA trusted by default
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
pytest.fixture(autouse=True)(httpbin_ca_bundle)
|
def httpbin_add_ca_bundle(monkeypatch):
|
||||||
|
"""
|
||||||
|
Make pytest-httpbin's CA trusted by default.
|
||||||
|
|
||||||
|
(Same as `httpbin_ca_bundle`, just auto-used.).
|
||||||
|
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv('REQUESTS_CA_BUNDLE', certs.where())
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def httpbin_secure_untrusted(monkeypatch, httpbin_secure):
|
def httpbin_secure_untrusted(monkeypatch, httpbin_secure):
|
||||||
"""Like the `httpbin_secure` fixture, but without the
|
"""
|
||||||
make-CA-trusted-by-default"""
|
Like the `httpbin_secure` fixture, but without the
|
||||||
|
make-CA-trusted-by-default.
|
||||||
|
|
||||||
|
"""
|
||||||
monkeypatch.delenv('REQUESTS_CA_BUNDLE')
|
monkeypatch.delenv('REQUESTS_CA_BUNDLE')
|
||||||
return httpbin_secure
|
return httpbin_secure
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import mock
|
import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from utils import http, add_auth, HTTP_OK, TestEnvironment
|
from utils import http, add_auth, HTTP_OK, MockEnvironment
|
||||||
import httpie.input
|
import httpie.input
|
||||||
import httpie.cli
|
import httpie.cli
|
||||||
|
|
||||||
@ -55,10 +55,10 @@ def test_credentials_in_url_auth_flag_has_priority(httpbin_both):
|
|||||||
])
|
])
|
||||||
def test_only_username_in_url(url):
|
def test_only_username_in_url(url):
|
||||||
"""
|
"""
|
||||||
https://github.com/jkbrzt/httpie/issues/242
|
https://github.com/jakubroztocil/httpie/issues/242
|
||||||
|
|
||||||
"""
|
"""
|
||||||
args = httpie.cli.parser.parse_args(args=[url], env=TestEnvironment())
|
args = httpie.cli.parser.parse_args(args=[url], env=MockEnvironment())
|
||||||
assert args.auth
|
assert args.auth
|
||||||
assert args.auth.username == 'username'
|
assert args.auth.username == 'username'
|
||||||
assert args.auth.password == ''
|
assert args.auth.password == ''
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
from fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG
|
from fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG
|
||||||
from httpie.compat import urlopen
|
from httpie.compat import urlopen
|
||||||
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
|
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
|
||||||
from utils import TestEnvironment, http
|
from utils import MockEnvironment, http
|
||||||
|
|
||||||
|
|
||||||
class TestBinaryRequestData:
|
class TestBinaryRequestData:
|
||||||
|
|
||||||
def test_binary_stdin(self, httpbin):
|
def test_binary_stdin(self, httpbin):
|
||||||
with open(BIN_FILE_PATH, 'rb') as stdin:
|
with open(BIN_FILE_PATH, 'rb') as stdin:
|
||||||
env = TestEnvironment(
|
env = MockEnvironment(
|
||||||
stdin=stdin,
|
stdin=stdin,
|
||||||
stdin_isatty=False,
|
stdin_isatty=False,
|
||||||
stdout_isatty=False
|
stdout_isatty=False
|
||||||
@ -18,13 +18,13 @@ class TestBinaryRequestData:
|
|||||||
assert r == BIN_FILE_CONTENT
|
assert r == BIN_FILE_CONTENT
|
||||||
|
|
||||||
def test_binary_file_path(self, httpbin):
|
def test_binary_file_path(self, httpbin):
|
||||||
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
|
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||||
r = http('--print=B', 'POST', httpbin.url + '/post',
|
r = http('--print=B', 'POST', httpbin.url + '/post',
|
||||||
'@' + BIN_FILE_PATH_ARG, env=env, )
|
'@' + BIN_FILE_PATH_ARG, env=env, )
|
||||||
assert r == BIN_FILE_CONTENT
|
assert r == BIN_FILE_CONTENT
|
||||||
|
|
||||||
def test_binary_file_form(self, httpbin):
|
def test_binary_file_form(self, httpbin):
|
||||||
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
|
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||||
r = http('--print=B', '--form', 'POST', httpbin.url + '/post',
|
r = http('--print=B', '--form', 'POST', httpbin.url + '/post',
|
||||||
'test@' + BIN_FILE_PATH_ARG, env=env)
|
'test@' + BIN_FILE_PATH_ARG, env=env)
|
||||||
assert bytes(BIN_FILE_CONTENT) in bytes(r)
|
assert bytes(BIN_FILE_CONTENT) in bytes(r)
|
||||||
@ -44,12 +44,12 @@ class TestBinaryResponseData:
|
|||||||
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
||||||
|
|
||||||
def test_binary_suppresses_when_not_terminal_but_pretty(self):
|
def test_binary_suppresses_when_not_terminal_but_pretty(self):
|
||||||
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
|
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||||
r = http('--pretty=all', 'GET', self.url,
|
r = http('--pretty=all', 'GET', self.url,
|
||||||
env=env)
|
env=env)
|
||||||
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
||||||
|
|
||||||
def test_binary_included_and_correct_when_suitable(self):
|
def test_binary_included_and_correct_when_suitable(self):
|
||||||
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
|
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||||
r = http('GET', self.url, env=env)
|
r = http('GET', self.url, env=env)
|
||||||
assert r == self.bindata
|
assert r == self.bindata
|
||||||
|
@ -10,7 +10,7 @@ from httpie import input
|
|||||||
from httpie.input import KeyValue, KeyValueArgType, DataDict
|
from httpie.input import KeyValue, KeyValueArgType, DataDict
|
||||||
from httpie import ExitStatus
|
from httpie import ExitStatus
|
||||||
from httpie.cli import parser
|
from httpie.cli import parser
|
||||||
from utils import TestEnvironment, http, HTTP_OK
|
from utils import MockEnvironment, http, HTTP_OK
|
||||||
from fixtures import (
|
from fixtures import (
|
||||||
FILE_PATH_ARG, JSON_FILE_PATH_ARG,
|
FILE_PATH_ARG, JSON_FILE_PATH_ARG,
|
||||||
JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH
|
JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH
|
||||||
@ -49,9 +49,9 @@ class TestItemParsing:
|
|||||||
assert 'bar@baz' in items.files
|
assert 'bar@baz' in items.files
|
||||||
|
|
||||||
@pytest.mark.parametrize(('string', 'key', 'sep', 'value'), [
|
@pytest.mark.parametrize(('string', 'key', 'sep', 'value'), [
|
||||||
('path=c:\windows', 'path', '=', 'c:\windows'),
|
('path=c:\\windows', 'path', '=', 'c:\\windows'),
|
||||||
('path=c:\windows\\', 'path', '=', 'c:\windows\\'),
|
('path=c:\\windows\\', 'path', '=', 'c:\\windows\\'),
|
||||||
('path\==c:\windows', 'path=', '=', 'c:\windows'),
|
('path\\==c:\\windows', 'path=', '=', 'c:\\windows'),
|
||||||
])
|
])
|
||||||
def test_backslash_before_non_special_character_does_not_escape(
|
def test_backslash_before_non_special_character_does_not_escape(
|
||||||
self, string, key, sep, value):
|
self, string, key, sep, value):
|
||||||
@ -161,44 +161,44 @@ class TestQuerystring:
|
|||||||
|
|
||||||
class TestLocalhostShorthand:
|
class TestLocalhostShorthand:
|
||||||
def test_expand_localhost_shorthand(self):
|
def test_expand_localhost_shorthand(self):
|
||||||
args = parser.parse_args(args=[':'], env=TestEnvironment())
|
args = parser.parse_args(args=[':'], env=MockEnvironment())
|
||||||
assert args.url == 'http://localhost'
|
assert args.url == 'http://localhost'
|
||||||
|
|
||||||
def test_expand_localhost_shorthand_with_slash(self):
|
def test_expand_localhost_shorthand_with_slash(self):
|
||||||
args = parser.parse_args(args=[':/'], env=TestEnvironment())
|
args = parser.parse_args(args=[':/'], env=MockEnvironment())
|
||||||
assert args.url == 'http://localhost/'
|
assert args.url == 'http://localhost/'
|
||||||
|
|
||||||
def test_expand_localhost_shorthand_with_port(self):
|
def test_expand_localhost_shorthand_with_port(self):
|
||||||
args = parser.parse_args(args=[':3000'], env=TestEnvironment())
|
args = parser.parse_args(args=[':3000'], env=MockEnvironment())
|
||||||
assert args.url == 'http://localhost:3000'
|
assert args.url == 'http://localhost:3000'
|
||||||
|
|
||||||
def test_expand_localhost_shorthand_with_path(self):
|
def test_expand_localhost_shorthand_with_path(self):
|
||||||
args = parser.parse_args(args=[':/path'], env=TestEnvironment())
|
args = parser.parse_args(args=[':/path'], env=MockEnvironment())
|
||||||
assert args.url == 'http://localhost/path'
|
assert args.url == 'http://localhost/path'
|
||||||
|
|
||||||
def test_expand_localhost_shorthand_with_port_and_slash(self):
|
def test_expand_localhost_shorthand_with_port_and_slash(self):
|
||||||
args = parser.parse_args(args=[':3000/'], env=TestEnvironment())
|
args = parser.parse_args(args=[':3000/'], env=MockEnvironment())
|
||||||
assert args.url == 'http://localhost:3000/'
|
assert args.url == 'http://localhost:3000/'
|
||||||
|
|
||||||
def test_expand_localhost_shorthand_with_port_and_path(self):
|
def test_expand_localhost_shorthand_with_port_and_path(self):
|
||||||
args = parser.parse_args(args=[':3000/path'], env=TestEnvironment())
|
args = parser.parse_args(args=[':3000/path'], env=MockEnvironment())
|
||||||
assert args.url == 'http://localhost:3000/path'
|
assert args.url == 'http://localhost:3000/path'
|
||||||
|
|
||||||
def test_dont_expand_shorthand_ipv6_as_shorthand(self):
|
def test_dont_expand_shorthand_ipv6_as_shorthand(self):
|
||||||
args = parser.parse_args(args=['::1'], env=TestEnvironment())
|
args = parser.parse_args(args=['::1'], env=MockEnvironment())
|
||||||
assert args.url == 'http://::1'
|
assert args.url == 'http://::1'
|
||||||
|
|
||||||
def test_dont_expand_longer_ipv6_as_shorthand(self):
|
def test_dont_expand_longer_ipv6_as_shorthand(self):
|
||||||
args = parser.parse_args(
|
args = parser.parse_args(
|
||||||
args=['::ffff:c000:0280'],
|
args=['::ffff:c000:0280'],
|
||||||
env=TestEnvironment()
|
env=MockEnvironment()
|
||||||
)
|
)
|
||||||
assert args.url == 'http://::ffff:c000:0280'
|
assert args.url == 'http://::ffff:c000:0280'
|
||||||
|
|
||||||
def test_dont_expand_full_ipv6_as_shorthand(self):
|
def test_dont_expand_full_ipv6_as_shorthand(self):
|
||||||
args = parser.parse_args(
|
args = parser.parse_args(
|
||||||
args=['0000:0000:0000:0000:0000:0000:0000:0001'],
|
args=['0000:0000:0000:0000:0000:0000:0000:0001'],
|
||||||
env=TestEnvironment()
|
env=MockEnvironment()
|
||||||
)
|
)
|
||||||
assert args.url == 'http://0000:0000:0000:0000:0000:0000:0000:0001'
|
assert args.url == 'http://0000:0000:0000:0000:0000:0000:0000:0001'
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ class TestArgumentParser:
|
|||||||
self.parser.args.items = []
|
self.parser.args.items = []
|
||||||
self.parser.args.ignore_stdin = False
|
self.parser.args.ignore_stdin = False
|
||||||
|
|
||||||
self.parser.env = TestEnvironment()
|
self.parser.env = MockEnvironment()
|
||||||
|
|
||||||
self.parser._guess_method()
|
self.parser._guess_method()
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ class TestArgumentParser:
|
|||||||
self.parser.args.url = 'http://example.com/'
|
self.parser.args.url = 'http://example.com/'
|
||||||
self.parser.args.items = []
|
self.parser.args.items = []
|
||||||
self.parser.args.ignore_stdin = False
|
self.parser.args.ignore_stdin = False
|
||||||
self.parser.env = TestEnvironment()
|
self.parser.env = MockEnvironment()
|
||||||
|
|
||||||
self.parser._guess_method()
|
self.parser._guess_method()
|
||||||
|
|
||||||
@ -243,7 +243,7 @@ class TestArgumentParser:
|
|||||||
self.parser.args.url = 'data=field'
|
self.parser.args.url = 'data=field'
|
||||||
self.parser.args.items = []
|
self.parser.args.items = []
|
||||||
self.parser.args.ignore_stdin = False
|
self.parser.args.ignore_stdin = False
|
||||||
self.parser.env = TestEnvironment()
|
self.parser.env = MockEnvironment()
|
||||||
self.parser._guess_method()
|
self.parser._guess_method()
|
||||||
|
|
||||||
assert self.parser.args.method == 'POST'
|
assert self.parser.args.method == 'POST'
|
||||||
@ -262,7 +262,7 @@ class TestArgumentParser:
|
|||||||
self.parser.args.items = []
|
self.parser.args.items = []
|
||||||
self.parser.args.ignore_stdin = False
|
self.parser.args.ignore_stdin = False
|
||||||
|
|
||||||
self.parser.env = TestEnvironment()
|
self.parser.env = MockEnvironment()
|
||||||
|
|
||||||
self.parser._guess_method()
|
self.parser._guess_method()
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ class TestArgumentParser:
|
|||||||
]
|
]
|
||||||
self.parser.args.ignore_stdin = False
|
self.parser.args.ignore_stdin = False
|
||||||
|
|
||||||
self.parser.env = TestEnvironment()
|
self.parser.env = MockEnvironment()
|
||||||
|
|
||||||
self.parser._guess_method()
|
self.parser._guess_method()
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ class TestIgnoreStdin:
|
|||||||
|
|
||||||
def test_ignore_stdin(self, httpbin):
|
def test_ignore_stdin(self, httpbin):
|
||||||
with open(FILE_PATH) as f:
|
with open(FILE_PATH) as f:
|
||||||
env = TestEnvironment(stdin=f, stdin_isatty=False)
|
env = MockEnvironment(stdin=f, stdin_isatty=False)
|
||||||
r = http('--ignore-stdin', '--verbose', httpbin.url + '/get',
|
r = http('--ignore-stdin', '--verbose', httpbin.url + '/get',
|
||||||
env=env)
|
env=env)
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
from utils import TestEnvironment, http
|
from httpie import __version__
|
||||||
|
from utils import MockEnvironment, http
|
||||||
|
from httpie.context import Environment
|
||||||
|
|
||||||
|
|
||||||
def test_default_options(httpbin):
|
def test_default_options(httpbin):
|
||||||
env = TestEnvironment()
|
env = MockEnvironment()
|
||||||
env.config['default_options'] = ['--form']
|
env.config['default_options'] = ['--form']
|
||||||
env.config.save()
|
env.config.save()
|
||||||
r = http(httpbin.url + '/post', 'foo=bar', env=env)
|
r = http(httpbin.url + '/post', 'foo=bar', env=env)
|
||||||
@ -10,7 +12,7 @@ def test_default_options(httpbin):
|
|||||||
|
|
||||||
|
|
||||||
def test_default_options_overwrite(httpbin):
|
def test_default_options_overwrite(httpbin):
|
||||||
env = TestEnvironment()
|
env = MockEnvironment()
|
||||||
env.config['default_options'] = ['--form']
|
env.config['default_options'] = ['--form']
|
||||||
env.config.save()
|
env.config.save()
|
||||||
r = http('--json', httpbin.url + '/post', 'foo=bar', env=env)
|
r = http('--json', httpbin.url + '/post', 'foo=bar', env=env)
|
||||||
@ -18,7 +20,7 @@ def test_default_options_overwrite(httpbin):
|
|||||||
|
|
||||||
|
|
||||||
def test_migrate_implicit_content_type():
|
def test_migrate_implicit_content_type():
|
||||||
config = TestEnvironment().config
|
config = MockEnvironment().config
|
||||||
|
|
||||||
config['implicit_content_type'] = 'json'
|
config['implicit_content_type'] = 'json'
|
||||||
config.save()
|
config.save()
|
||||||
@ -31,3 +33,8 @@ def test_migrate_implicit_content_type():
|
|||||||
config.load()
|
config.load()
|
||||||
assert 'implicit_content_type' not in config
|
assert 'implicit_content_type' not in config
|
||||||
assert config['default_options'] == ['--form']
|
assert config['default_options'] == ['--form']
|
||||||
|
|
||||||
|
|
||||||
|
def test_current_version():
|
||||||
|
version = Environment().config['__meta__']['httpie']
|
||||||
|
assert version == __version__
|
||||||
|
@ -3,10 +3,25 @@ Tests for the provided defaults regarding HTTP method, and --json vs. --form.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from httpie.client import JSON_ACCEPT
|
from httpie.client import JSON_ACCEPT
|
||||||
from utils import TestEnvironment, http, HTTP_OK
|
from utils import MockEnvironment, http, HTTP_OK
|
||||||
from fixtures import FILE_PATH
|
from fixtures import FILE_PATH
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_headers_case_insensitive(httpbin):
|
||||||
|
"""
|
||||||
|
<https://github.com/jakubroztocil/httpie/issues/644>
|
||||||
|
"""
|
||||||
|
r = http(
|
||||||
|
'--debug',
|
||||||
|
'--print=H',
|
||||||
|
httpbin.url + '/post',
|
||||||
|
'CONTENT-TYPE:application/json-patch+json',
|
||||||
|
'a=b',
|
||||||
|
)
|
||||||
|
assert 'CONTENT-TYPE: application/json-patch+json' in r
|
||||||
|
assert 'Content-Type' not in r
|
||||||
|
|
||||||
|
|
||||||
class TestImplicitHTTPMethod:
|
class TestImplicitHTTPMethod:
|
||||||
def test_implicit_GET(self, httpbin):
|
def test_implicit_GET(self, httpbin):
|
||||||
r = http(httpbin.url + '/get')
|
r = http(httpbin.url + '/get')
|
||||||
@ -29,7 +44,7 @@ class TestImplicitHTTPMethod:
|
|||||||
|
|
||||||
def test_implicit_POST_stdin(self, httpbin):
|
def test_implicit_POST_stdin(self, httpbin):
|
||||||
with open(FILE_PATH) as f:
|
with open(FILE_PATH) as f:
|
||||||
env = TestEnvironment(stdin_isatty=False, stdin=f)
|
env = MockEnvironment(stdin_isatty=False, stdin=f)
|
||||||
r = http('--form', httpbin.url + '/post', env=env)
|
r = http('--form', httpbin.url + '/post', env=env)
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
|
|
||||||
@ -43,7 +58,7 @@ class TestAutoContentTypeAndAcceptHeaders:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def test_GET_no_data_no_auto_headers(self, httpbin):
|
def test_GET_no_data_no_auto_headers(self, httpbin):
|
||||||
# https://github.com/jkbrzt/httpie/issues/62
|
# https://github.com/jakubroztocil/httpie/issues/62
|
||||||
r = http('GET', httpbin.url + '/headers')
|
r = http('GET', httpbin.url + '/headers')
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert r.json['headers']['Accept'] == '*/*'
|
assert r.json['headers']['Accept'] == '*/*'
|
||||||
@ -74,7 +89,7 @@ class TestAutoContentTypeAndAcceptHeaders:
|
|||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert r.json['headers']['Accept'] == JSON_ACCEPT
|
assert r.json['headers']['Accept'] == JSON_ACCEPT
|
||||||
# Make sure Content-Type gets set even with no data.
|
# Make sure Content-Type gets set even with no data.
|
||||||
# https://github.com/jkbrzt/httpie/issues/137
|
# https://github.com/jakubroztocil/httpie/issues/137
|
||||||
assert 'application/json' in r.json['headers']['Content-Type']
|
assert 'application/json' in r.json['headers']['Content-Type']
|
||||||
|
|
||||||
def test_GET_explicit_JSON_explicit_headers(self, httpbin):
|
def test_GET_explicit_JSON_explicit_headers(self, httpbin):
|
||||||
@ -97,11 +112,11 @@ class TestAutoContentTypeAndAcceptHeaders:
|
|||||||
assert '"Content-Type": "application/xml"' in r
|
assert '"Content-Type": "application/xml"' in r
|
||||||
|
|
||||||
def test_print_only_body_when_stdout_redirected_by_default(self, httpbin):
|
def test_print_only_body_when_stdout_redirected_by_default(self, httpbin):
|
||||||
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
|
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||||
r = http('GET', httpbin.url + '/get', env=env)
|
r = http('GET', httpbin.url + '/get', env=env)
|
||||||
assert 'HTTP/' not in r
|
assert 'HTTP/' not in r
|
||||||
|
|
||||||
def test_print_overridable_when_stdout_redirected(self, httpbin):
|
def test_print_overridable_when_stdout_redirected(self, httpbin):
|
||||||
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
|
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||||
r = http('--print=h', 'GET', httpbin.url + '/get', env=env)
|
r = http('--print=h', 'GET', httpbin.url + '/get', env=env)
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
|
@ -10,7 +10,7 @@ from httpie.downloads import (
|
|||||||
parse_content_range, filename_from_content_disposition, filename_from_url,
|
parse_content_range, filename_from_content_disposition, filename_from_url,
|
||||||
get_unique_filename, ContentRangeError, Downloader,
|
get_unique_filename, ContentRangeError, Downloader,
|
||||||
)
|
)
|
||||||
from utils import http, TestEnvironment
|
from utils import http, MockEnvironment
|
||||||
|
|
||||||
|
|
||||||
class Response(object):
|
class Response(object):
|
||||||
@ -123,7 +123,7 @@ class TestDownloads:
|
|||||||
def test_actual_download(self, httpbin_both, httpbin):
|
def test_actual_download(self, httpbin_both, httpbin):
|
||||||
robots_txt = '/robots.txt'
|
robots_txt = '/robots.txt'
|
||||||
body = urlopen(httpbin + robots_txt).read().decode()
|
body = urlopen(httpbin + robots_txt).read().decode()
|
||||||
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
|
env = MockEnvironment(stdin_isatty=True, stdout_isatty=False)
|
||||||
r = http('--download', httpbin_both.url + robots_txt, env=env)
|
r = http('--download', httpbin_both.url + robots_txt, env=env)
|
||||||
assert 'Downloading' in r.stderr
|
assert 'Downloading' in r.stderr
|
||||||
assert '[K' in r.stderr
|
assert '[K' in r.stderr
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
from httpie import ExitStatus
|
from httpie import ExitStatus
|
||||||
from utils import TestEnvironment, http, HTTP_OK
|
from utils import MockEnvironment, http, HTTP_OK
|
||||||
|
|
||||||
|
|
||||||
def test_keyboard_interrupt_during_arg_parsing_exit_status(httpbin):
|
def test_keyboard_interrupt_during_arg_parsing_exit_status(httpbin):
|
||||||
@ -21,26 +21,26 @@ def test_keyboard_interrupt_in_program_exit_status(httpbin):
|
|||||||
def test_ok_response_exits_0(httpbin):
|
def test_ok_response_exits_0(httpbin):
|
||||||
r = http('GET', httpbin.url + '/get')
|
r = http('GET', httpbin.url + '/get')
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert r.exit_status == ExitStatus.OK
|
assert r.exit_status == ExitStatus.SUCCESS
|
||||||
|
|
||||||
|
|
||||||
def test_error_response_exits_0_without_check_status(httpbin):
|
def test_error_response_exits_0_without_check_status(httpbin):
|
||||||
r = http('GET', httpbin.url + '/status/500')
|
r = http('GET', httpbin.url + '/status/500')
|
||||||
assert '500 INTERNAL SERVER ERRO' in r
|
assert '500 INTERNAL SERVER ERROR' in r
|
||||||
assert r.exit_status == ExitStatus.OK
|
assert r.exit_status == ExitStatus.SUCCESS
|
||||||
assert not r.stderr
|
assert not r.stderr
|
||||||
|
|
||||||
|
|
||||||
def test_timeout_exit_status(httpbin):
|
def test_timeout_exit_status(httpbin):
|
||||||
|
|
||||||
r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.02',
|
r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.5',
|
||||||
error_exit_ok=True)
|
error_exit_ok=True)
|
||||||
assert r.exit_status == ExitStatus.ERROR_TIMEOUT
|
assert r.exit_status == ExitStatus.ERROR_TIMEOUT
|
||||||
|
|
||||||
|
|
||||||
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(
|
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(
|
||||||
httpbin):
|
httpbin):
|
||||||
env = TestEnvironment(stdout_isatty=False)
|
env = MockEnvironment(stdout_isatty=False)
|
||||||
r = http('--check-status', '--headers',
|
r = http('--check-status', '--headers',
|
||||||
'GET', httpbin.url + '/status/301',
|
'GET', httpbin.url + '/status/301',
|
||||||
env=env, error_exit_ok=True)
|
env=env, error_exit_ok=True)
|
||||||
@ -55,7 +55,7 @@ def test_3xx_check_status_redirects_allowed_exits_0(httpbin):
|
|||||||
error_exit_ok=True)
|
error_exit_ok=True)
|
||||||
# The redirect will be followed so 200 is expected.
|
# The redirect will be followed so 200 is expected.
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert r.exit_status == ExitStatus.OK
|
assert r.exit_status == ExitStatus.SUCCESS
|
||||||
|
|
||||||
|
|
||||||
def test_4xx_check_status_exits_4(httpbin):
|
def test_4xx_check_status_exits_4(httpbin):
|
||||||
|
@ -2,28 +2,27 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from httpie.input import ParseError
|
from httpie.input import ParseError
|
||||||
from utils import TestEnvironment, http, HTTP_OK
|
from utils import MockEnvironment, http, HTTP_OK
|
||||||
from fixtures import FILE_PATH, FILE_CONTENT
|
from fixtures import FILE_PATH, FILE_CONTENT
|
||||||
|
|
||||||
import httpie
|
import httpie
|
||||||
from httpie.compat import is_py26
|
|
||||||
|
|
||||||
|
|
||||||
def test_debug():
|
def test_debug():
|
||||||
r = http('--debug')
|
r = http('--debug')
|
||||||
assert r.exit_status == httpie.ExitStatus.OK
|
assert r.exit_status == httpie.ExitStatus.SUCCESS
|
||||||
assert 'HTTPie %s' % httpie.__version__ in r.stderr
|
assert 'HTTPie %s' % httpie.__version__ in r.stderr
|
||||||
|
|
||||||
|
|
||||||
def test_help():
|
def test_help():
|
||||||
r = http('--help', error_exit_ok=True)
|
r = http('--help', error_exit_ok=True)
|
||||||
assert r.exit_status == httpie.ExitStatus.OK
|
assert r.exit_status == httpie.ExitStatus.SUCCESS
|
||||||
assert 'https://github.com/jkbrzt/httpie/issues' in r
|
assert 'https://github.com/jakubroztocil/httpie/issues' in r
|
||||||
|
|
||||||
|
|
||||||
def test_version():
|
def test_version():
|
||||||
r = http('--version', error_exit_ok=True)
|
r = http('--version', error_exit_ok=True)
|
||||||
assert r.exit_status == httpie.ExitStatus.OK
|
assert r.exit_status == httpie.ExitStatus.SUCCESS
|
||||||
# FIXME: py3 has version in stdout, py2 in stderr
|
# FIXME: py3 has version in stdout, py2 in stderr
|
||||||
assert httpie.__version__ == r.stderr.strip() + r.strip()
|
assert httpie.__version__ == r.stderr.strip() + r.strip()
|
||||||
|
|
||||||
@ -64,7 +63,7 @@ def test_POST_form_multiple_values(httpbin_both):
|
|||||||
|
|
||||||
def test_POST_stdin(httpbin_both):
|
def test_POST_stdin(httpbin_both):
|
||||||
with open(FILE_PATH) as f:
|
with open(FILE_PATH) as f:
|
||||||
env = TestEnvironment(stdin=f, stdin_isatty=False)
|
env = MockEnvironment(stdin=f, stdin_isatty=False)
|
||||||
r = http('--form', 'POST', httpbin_both + '/post', env=env)
|
r = http('--form', 'POST', httpbin_both + '/post', env=env)
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert FILE_CONTENT in r
|
assert FILE_CONTENT in r
|
||||||
@ -107,10 +106,6 @@ def test_headers_empty_value_with_value_gives_error(httpbin):
|
|||||||
http('GET', httpbin + '/headers', 'Accept;SYNTAX_ERROR')
|
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'
|
|
||||||
)
|
|
||||||
def test_json_input_preserve_order(httpbin_both):
|
def test_json_input_preserve_order(httpbin_both):
|
||||||
r = http('PATCH', httpbin_both + '/patch',
|
r = http('PATCH', httpbin_both + '/patch',
|
||||||
'order:={"map":{"1":"first","2":"second"}}')
|
'order:={"map":{"1":"first","2":"second"}}')
|
||||||
|
@ -3,7 +3,7 @@ from tempfile import gettempdir
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from utils import TestEnvironment, http, HTTP_OK, COLOR, CRLF
|
from utils import MockEnvironment, http, HTTP_OK, COLOR, CRLF
|
||||||
from httpie import ExitStatus
|
from httpie import ExitStatus
|
||||||
from httpie.compat import urlopen
|
from httpie.compat import urlopen
|
||||||
from httpie.output.formatters.colors import get_lexer
|
from httpie.output.formatters.colors import get_lexer
|
||||||
@ -15,7 +15,7 @@ def test_output_option(httpbin, stdout_isatty):
|
|||||||
url = httpbin + '/robots.txt'
|
url = httpbin + '/robots.txt'
|
||||||
|
|
||||||
r = http('--output', output_filename, url,
|
r = http('--output', output_filename, url,
|
||||||
env=TestEnvironment(stdout_isatty=stdout_isatty))
|
env=MockEnvironment(stdout_isatty=stdout_isatty))
|
||||||
assert r == ''
|
assert r == ''
|
||||||
|
|
||||||
expected_body = urlopen(url).read().decode()
|
expected_body = urlopen(url).read().decode()
|
||||||
@ -33,7 +33,7 @@ class TestVerboseFlag:
|
|||||||
assert r.count('__test__') == 2
|
assert r.count('__test__') == 2
|
||||||
|
|
||||||
def test_verbose_form(self, httpbin):
|
def test_verbose_form(self, httpbin):
|
||||||
# https://github.com/jkbrzt/httpie/issues/53
|
# https://github.com/jakubroztocil/httpie/issues/53
|
||||||
r = http('--verbose', '--form', 'POST', httpbin.url + '/post',
|
r = http('--verbose', '--form', 'POST', httpbin.url + '/post',
|
||||||
'A=B', 'C=D')
|
'A=B', 'C=D')
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
@ -86,7 +86,7 @@ class TestPrettyOptions:
|
|||||||
"""Test the --pretty flag handling."""
|
"""Test the --pretty flag handling."""
|
||||||
|
|
||||||
def test_pretty_enabled_by_default(self, httpbin):
|
def test_pretty_enabled_by_default(self, httpbin):
|
||||||
env = TestEnvironment(colors=256)
|
env = MockEnvironment(colors=256)
|
||||||
r = http('GET', httpbin.url + '/get', env=env)
|
r = http('GET', httpbin.url + '/get', env=env)
|
||||||
assert COLOR in r
|
assert COLOR in r
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ class TestPrettyOptions:
|
|||||||
assert COLOR not in r
|
assert COLOR not in r
|
||||||
|
|
||||||
def test_force_pretty(self, httpbin):
|
def test_force_pretty(self, httpbin):
|
||||||
env = TestEnvironment(stdout_isatty=False, colors=256)
|
env = MockEnvironment(stdout_isatty=False, colors=256)
|
||||||
r = http('--pretty=all', 'GET', httpbin.url + '/get', env=env, )
|
r = http('--pretty=all', 'GET', httpbin.url + '/get', env=env, )
|
||||||
assert COLOR in r
|
assert COLOR in r
|
||||||
|
|
||||||
@ -108,13 +108,13 @@ class TestPrettyOptions:
|
|||||||
match any lexer.
|
match any lexer.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
env = TestEnvironment(colors=256)
|
env = MockEnvironment(colors=256)
|
||||||
r = http('--print=B', '--pretty=all', httpbin.url + '/post',
|
r = http('--print=B', '--pretty=all', httpbin.url + '/post',
|
||||||
'Content-Type:text/foo+json', 'a=b', env=env)
|
'Content-Type:text/foo+json', 'a=b', env=env)
|
||||||
assert COLOR in r
|
assert COLOR in r
|
||||||
|
|
||||||
def test_colors_option(self, httpbin):
|
def test_colors_option(self, httpbin):
|
||||||
env = TestEnvironment(colors=256)
|
env = MockEnvironment(colors=256)
|
||||||
r = http('--print=B', '--pretty=colors',
|
r = http('--print=B', '--pretty=colors',
|
||||||
'GET', httpbin.url + '/get', 'a=b',
|
'GET', httpbin.url + '/get', 'a=b',
|
||||||
env=env)
|
env=env)
|
||||||
@ -123,7 +123,7 @@ class TestPrettyOptions:
|
|||||||
assert COLOR in r
|
assert COLOR in r
|
||||||
|
|
||||||
def test_format_option(self, httpbin):
|
def test_format_option(self, httpbin):
|
||||||
env = TestEnvironment(colors=256)
|
env = MockEnvironment(colors=256)
|
||||||
r = http('--print=B', '--pretty=format',
|
r = http('--print=B', '--pretty=format',
|
||||||
'GET', httpbin.url + '/get', 'a=b',
|
'GET', httpbin.url + '/get', 'a=b',
|
||||||
env=env)
|
env=env)
|
||||||
@ -161,7 +161,7 @@ class TestLineEndings:
|
|||||||
|
|
||||||
def test_CRLF_formatted_response(self, httpbin):
|
def test_CRLF_formatted_response(self, httpbin):
|
||||||
r = http('--pretty=format', 'GET', httpbin.url + '/get')
|
r = http('--pretty=format', 'GET', httpbin.url + '/get')
|
||||||
assert r.exit_status == ExitStatus.OK
|
assert r.exit_status == ExitStatus.SUCCESS
|
||||||
self._validate_crlf(r)
|
self._validate_crlf(r)
|
||||||
|
|
||||||
def test_CRLF_ugly_request(self, httpbin):
|
def test_CRLF_ugly_request(self, httpbin):
|
||||||
|
@ -7,7 +7,7 @@ from httpie.compat import is_windows
|
|||||||
|
|
||||||
def test_Host_header_overwrite(httpbin):
|
def test_Host_header_overwrite(httpbin):
|
||||||
"""
|
"""
|
||||||
https://github.com/jkbrzt/httpie/issues/235
|
https://github.com/jakubroztocil/httpie/issues/235
|
||||||
|
|
||||||
"""
|
"""
|
||||||
host = 'httpbin.org'
|
host = 'httpbin.org'
|
||||||
@ -21,7 +21,7 @@ def test_Host_header_overwrite(httpbin):
|
|||||||
@pytest.mark.skipif(is_windows, reason='Unix-only')
|
@pytest.mark.skipif(is_windows, reason='Unix-only')
|
||||||
def test_output_devnull(httpbin):
|
def test_output_devnull(httpbin):
|
||||||
"""
|
"""
|
||||||
https://github.com/jkbrzt/httpie/issues/252
|
https://github.com/jakubroztocil/httpie/issues/252
|
||||||
|
|
||||||
"""
|
"""
|
||||||
http('--output=/dev/null', httpbin + '/get')
|
http('--output=/dev/null', httpbin + '/get')
|
||||||
|
@ -7,7 +7,7 @@ from tempfile import gettempdir
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from httpie.plugins.builtin import HTTPBasicAuth
|
from httpie.plugins.builtin import HTTPBasicAuth
|
||||||
from utils import TestEnvironment, mk_config_dir, http, HTTP_OK
|
from utils import MockEnvironment, mk_config_dir, http, HTTP_OK
|
||||||
from fixtures import UNICODE
|
from fixtures import UNICODE
|
||||||
|
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class SessionTestBase(object):
|
|||||||
for session files being reused.
|
for session files being reused.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return TestEnvironment(config_dir=self.config_dir)
|
return MockEnvironment(config_dir=self.config_dir)
|
||||||
|
|
||||||
|
|
||||||
class TestSessionFlow(SessionTestBase):
|
class TestSessionFlow(SessionTestBase):
|
||||||
@ -81,8 +81,8 @@ class TestSessionFlow(SessionTestBase):
|
|||||||
assert HTTP_OK in r4
|
assert HTTP_OK in r4
|
||||||
assert r4.json['headers']['Hello'] == 'World2'
|
assert r4.json['headers']['Hello'] == 'World2'
|
||||||
assert r4.json['headers']['Cookie'] == 'hello=world2'
|
assert r4.json['headers']['Cookie'] == 'hello=world2'
|
||||||
assert (r2.json['headers']['Authorization'] !=
|
assert (r2.json['headers']['Authorization']
|
||||||
r4.json['headers']['Authorization'])
|
!= r4.json['headers']['Authorization'])
|
||||||
|
|
||||||
def test_session_read_only(self, httpbin):
|
def test_session_read_only(self, httpbin):
|
||||||
self.start_session(httpbin)
|
self.start_session(httpbin)
|
||||||
@ -143,7 +143,7 @@ class TestSession(SessionTestBase):
|
|||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
sys.version_info >= (3,),
|
sys.version_info >= (3,),
|
||||||
reason="This test fails intermittently on Python 3 - "
|
reason="This test fails intermittently on Python 3 - "
|
||||||
"see https://github.com/jkbrzt/httpie/issues/282")
|
"see https://github.com/jakubroztocil/httpie/issues/282")
|
||||||
def test_session_unicode(self, httpbin):
|
def test_session_unicode(self, httpbin):
|
||||||
self.start_session(httpbin)
|
self.start_session(httpbin)
|
||||||
|
|
||||||
@ -157,14 +157,14 @@ class TestSession(SessionTestBase):
|
|||||||
assert HTTP_OK in r2
|
assert HTTP_OK in r2
|
||||||
|
|
||||||
# FIXME: Authorization *sometimes* is not present on Python3
|
# FIXME: Authorization *sometimes* is not present on Python3
|
||||||
assert (r2.json['headers']['Authorization'] ==
|
assert (r2.json['headers']['Authorization']
|
||||||
HTTPBasicAuth.make_header(u'test', UNICODE))
|
== HTTPBasicAuth.make_header(u'test', UNICODE))
|
||||||
# httpbin doesn't interpret utf8 headers
|
# httpbin doesn't interpret utf8 headers
|
||||||
assert UNICODE in r2
|
assert UNICODE in r2
|
||||||
|
|
||||||
def test_session_default_header_value_overwritten(self, httpbin):
|
def test_session_default_header_value_overwritten(self, httpbin):
|
||||||
self.start_session(httpbin)
|
self.start_session(httpbin)
|
||||||
# https://github.com/jkbrzt/httpie/issues/180
|
# https://github.com/jakubroztocil/httpie/issues/180
|
||||||
r1 = http('--session=test',
|
r1 = http('--session=test',
|
||||||
httpbin.url + '/headers', 'User-Agent:custom',
|
httpbin.url + '/headers', 'User-Agent:custom',
|
||||||
env=self.env())
|
env=self.env())
|
||||||
@ -176,7 +176,7 @@ class TestSession(SessionTestBase):
|
|||||||
assert r2.json['headers']['User-Agent'] == 'custom'
|
assert r2.json['headers']['User-Agent'] == 'custom'
|
||||||
|
|
||||||
def test_download_in_session(self, httpbin):
|
def test_download_in_session(self, httpbin):
|
||||||
# https://github.com/jkbrzt/httpie/issues/412
|
# https://github.com/jakubroztocil/httpie/issues/412
|
||||||
self.start_session(httpbin)
|
self.start_session(httpbin)
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
os.chdir(gettempdir())
|
os.chdir(gettempdir())
|
||||||
|
@ -73,6 +73,11 @@ class TestServerCert:
|
|||||||
r = http(httpbin_secure.url + '/get', '--verify=no')
|
r = http(httpbin_secure.url + '/get', '--verify=no')
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('verify_value', ['false', 'fALse'])
|
||||||
|
def test_verify_false_OK(self, httpbin_secure, verify_value):
|
||||||
|
r = http(httpbin_secure.url + '/get', '--verify', verify_value)
|
||||||
|
assert HTTP_OK in r
|
||||||
|
|
||||||
def test_verify_custom_ca_bundle_path(
|
def test_verify_custom_ca_bundle_path(
|
||||||
self, httpbin_secure_untrusted):
|
self, httpbin_secure_untrusted):
|
||||||
r = http(httpbin_secure_untrusted + '/get', '--verify', CA_BUNDLE)
|
r = http(httpbin_secure_untrusted + '/get', '--verify', CA_BUNDLE)
|
||||||
@ -85,7 +90,8 @@ class TestServerCert:
|
|||||||
http(httpbin_secure_untrusted.url + '/get')
|
http(httpbin_secure_untrusted.url + '/get')
|
||||||
|
|
||||||
def test_verify_custom_ca_bundle_invalid_path(self, httpbin_secure):
|
def test_verify_custom_ca_bundle_invalid_path(self, httpbin_secure):
|
||||||
with pytest.raises(SSLError):
|
# since 2.14.0 requests raises IOError
|
||||||
|
with pytest.raises((SSLError, IOError)):
|
||||||
http(httpbin_secure.url + '/get', '--verify', '/__not_found__')
|
http(httpbin_secure.url + '/get', '--verify', '/__not_found__')
|
||||||
|
|
||||||
def test_verify_custom_ca_bundle_invalid_bundle(self, httpbin_secure):
|
def test_verify_custom_ca_bundle_invalid_bundle(self, httpbin_secure):
|
||||||
|
@ -2,7 +2,7 @@ import pytest
|
|||||||
|
|
||||||
from httpie.compat import is_windows
|
from httpie.compat import is_windows
|
||||||
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
|
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
|
||||||
from utils import http, TestEnvironment
|
from utils import http, MockEnvironment
|
||||||
from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH
|
from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH
|
|||||||
def test_pretty_redirected_stream(httpbin):
|
def test_pretty_redirected_stream(httpbin):
|
||||||
"""Test that --stream works with prettified redirected output."""
|
"""Test that --stream works with prettified redirected output."""
|
||||||
with open(BIN_FILE_PATH, 'rb') as f:
|
with open(BIN_FILE_PATH, 'rb') as f:
|
||||||
env = TestEnvironment(colors=256, stdin=f,
|
env = MockEnvironment(colors=256, stdin=f,
|
||||||
stdin_isatty=False,
|
stdin_isatty=False,
|
||||||
stdout_isatty=False)
|
stdout_isatty=False)
|
||||||
r = http('--verbose', '--pretty=all', '--stream', 'GET',
|
r = http('--verbose', '--pretty=all', '--stream', 'GET',
|
||||||
@ -26,7 +26,7 @@ def test_encoded_stream(httpbin):
|
|||||||
"""Test that --stream works with non-prettified
|
"""Test that --stream works with non-prettified
|
||||||
redirected terminal output."""
|
redirected terminal output."""
|
||||||
with open(BIN_FILE_PATH, 'rb') as f:
|
with open(BIN_FILE_PATH, 'rb') as f:
|
||||||
env = TestEnvironment(stdin=f, stdin_isatty=False)
|
env = MockEnvironment(stdin=f, stdin_isatty=False)
|
||||||
r = http('--pretty=none', '--stream', '--verbose', 'GET',
|
r = http('--pretty=none', '--stream', '--verbose', 'GET',
|
||||||
httpbin.url + '/get', env=env)
|
httpbin.url + '/get', env=env)
|
||||||
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
||||||
@ -36,7 +36,7 @@ def test_redirected_stream(httpbin):
|
|||||||
"""Test that --stream works with non-prettified
|
"""Test that --stream works with non-prettified
|
||||||
redirected terminal output."""
|
redirected terminal output."""
|
||||||
with open(BIN_FILE_PATH, 'rb') as f:
|
with open(BIN_FILE_PATH, 'rb') as f:
|
||||||
env = TestEnvironment(stdout_isatty=False,
|
env = MockEnvironment(stdout_isatty=False,
|
||||||
stdin_isatty=False,
|
stdin_isatty=False,
|
||||||
stdin=f)
|
stdin=f)
|
||||||
r = http('--pretty=none', '--stream', '--verbose', 'GET',
|
r = http('--pretty=none', '--stream', '--verbose', 'GET',
|
||||||
|
@ -3,7 +3,7 @@ import os
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from httpie.input import ParseError
|
from httpie.input import ParseError
|
||||||
from utils import TestEnvironment, http, HTTP_OK
|
from utils import MockEnvironment, http, HTTP_OK
|
||||||
from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT
|
from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT
|
||||||
|
|
||||||
|
|
||||||
@ -62,14 +62,14 @@ class TestRequestBodyFromFilePath:
|
|||||||
|
|
||||||
def test_request_body_from_file_by_path_no_field_name_allowed(
|
def test_request_body_from_file_by_path_no_field_name_allowed(
|
||||||
self, httpbin):
|
self, httpbin):
|
||||||
env = TestEnvironment(stdin_isatty=True)
|
env = MockEnvironment(stdin_isatty=True)
|
||||||
r = http('POST', httpbin.url + '/post', 'field-name@' + FILE_PATH_ARG,
|
r = http('POST', httpbin.url + '/post', 'field-name@' + FILE_PATH_ARG,
|
||||||
env=env, error_exit_ok=True)
|
env=env, error_exit_ok=True)
|
||||||
assert 'perhaps you meant --form?' in r.stderr
|
assert 'perhaps you meant --form?' in r.stderr
|
||||||
|
|
||||||
def test_request_body_from_file_by_path_no_data_items_allowed(
|
def test_request_body_from_file_by_path_no_data_items_allowed(
|
||||||
self, httpbin):
|
self, httpbin):
|
||||||
env = TestEnvironment(stdin_isatty=False)
|
env = MockEnvironment(stdin_isatty=False)
|
||||||
r = http('POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, 'foo=bar',
|
r = http('POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, 'foo=bar',
|
||||||
env=env, error_exit_ok=True)
|
env=env, error_exit_ok=True)
|
||||||
assert 'cannot be mixed' in r.stderr
|
assert 'cannot be mixed' in r.stderr
|
||||||
|
@ -4,7 +4,7 @@ import tempfile
|
|||||||
import pytest
|
import pytest
|
||||||
from httpie.context import Environment
|
from httpie.context import Environment
|
||||||
|
|
||||||
from utils import TestEnvironment, http
|
from utils import MockEnvironment, http
|
||||||
from httpie.compat import is_windows
|
from httpie.compat import is_windows
|
||||||
|
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ class TestWindowsOnly:
|
|||||||
|
|
||||||
class TestFakeWindows:
|
class TestFakeWindows:
|
||||||
def test_output_file_pretty_not_allowed_on_windows(self, httpbin):
|
def test_output_file_pretty_not_allowed_on_windows(self, httpbin):
|
||||||
env = TestEnvironment(is_windows=True)
|
env = MockEnvironment(is_windows=True)
|
||||||
output_file = os.path.join(
|
output_file = os.path.join(
|
||||||
tempfile.gettempdir(),
|
tempfile.gettempdir(),
|
||||||
self.test_output_file_pretty_not_allowed_on_windows.__name__
|
self.test_output_file_pretty_not_allowed_on_windows.__name__
|
||||||
|
@ -33,7 +33,7 @@ def add_auth(url, auth):
|
|||||||
return proto + '://' + auth + '@' + rest
|
return proto + '://' + auth + '@' + rest
|
||||||
|
|
||||||
|
|
||||||
class TestEnvironment(Environment):
|
class MockEnvironment(Environment):
|
||||||
"""Environment subclass with reasonable defaults for testing."""
|
"""Environment subclass with reasonable defaults for testing."""
|
||||||
colors = 0
|
colors = 0
|
||||||
stdin_isatty = True,
|
stdin_isatty = True,
|
||||||
@ -51,7 +51,7 @@ class TestEnvironment(Environment):
|
|||||||
mode='w+t',
|
mode='w+t',
|
||||||
prefix='httpie_stderr'
|
prefix='httpie_stderr'
|
||||||
)
|
)
|
||||||
super(TestEnvironment, self).__init__(**kwargs)
|
super(MockEnvironment, self).__init__(**kwargs)
|
||||||
self._delete_config_dir = False
|
self._delete_config_dir = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -59,7 +59,7 @@ class TestEnvironment(Environment):
|
|||||||
if not self.config_dir.startswith(tempfile.gettempdir()):
|
if not self.config_dir.startswith(tempfile.gettempdir()):
|
||||||
self.config_dir = mk_config_dir()
|
self.config_dir = mk_config_dir()
|
||||||
self._delete_config_dir = True
|
self._delete_config_dir = True
|
||||||
return super(TestEnvironment, self).config
|
return super(MockEnvironment, self).config
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
if self._delete_config_dir:
|
if self._delete_config_dir:
|
||||||
@ -119,8 +119,8 @@ class StrCLIResponse(str, BaseCLIResponse):
|
|||||||
elif self.strip().startswith('{'):
|
elif self.strip().startswith('{'):
|
||||||
# Looks like JSON body.
|
# Looks like JSON body.
|
||||||
self._json = json.loads(self)
|
self._json = json.loads(self)
|
||||||
elif (self.count('Content-Type:') == 1 and
|
elif (self.count('Content-Type:') == 1
|
||||||
'application/json' in self):
|
and 'application/json' in self):
|
||||||
# Looks like a whole JSON HTTP message,
|
# Looks like a whole JSON HTTP message,
|
||||||
# try to extract its body.
|
# try to extract its body.
|
||||||
try:
|
try:
|
||||||
@ -183,7 +183,7 @@ def http(*args, **kwargs):
|
|||||||
error_exit_ok = kwargs.pop('error_exit_ok', False)
|
error_exit_ok = kwargs.pop('error_exit_ok', False)
|
||||||
env = kwargs.get('env')
|
env = kwargs.get('env')
|
||||||
if not env:
|
if not env:
|
||||||
env = kwargs['env'] = TestEnvironment()
|
env = kwargs['env'] = MockEnvironment()
|
||||||
|
|
||||||
stdout = env.stdout
|
stdout = env.stdout
|
||||||
stderr = env.stderr
|
stderr = env.stderr
|
||||||
@ -219,7 +219,7 @@ def http(*args, **kwargs):
|
|||||||
sys.stderr.write(stderr.read())
|
sys.stderr.write(stderr.read())
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
if not error_exit_ok and exit_status != ExitStatus.OK:
|
if not error_exit_ok and exit_status != ExitStatus.SUCCESS:
|
||||||
dump_stderr()
|
dump_stderr()
|
||||||
raise ExitStatusError(
|
raise ExitStatusError(
|
||||||
'httpie.core.main() unexpectedly returned'
|
'httpie.core.main() unexpectedly returned'
|
||||||
@ -243,7 +243,7 @@ def http(*args, **kwargs):
|
|||||||
r.stderr = stderr.read()
|
r.stderr = stderr.read()
|
||||||
r.exit_status = exit_status
|
r.exit_status = exit_status
|
||||||
|
|
||||||
if r.exit_status != ExitStatus.OK:
|
if r.exit_status != ExitStatus.SUCCESS:
|
||||||
sys.stderr.write(r.stderr)
|
sys.stderr.write(r.stderr)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
12
tox.ini
12
tox.ini
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
|
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py26, py27, py35, pypy, codestyle
|
# pypy3 currently fails because of a Flask issue
|
||||||
|
envlist = py27, py37, pypy
|
||||||
|
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
@ -21,10 +22,5 @@ commands =
|
|||||||
--doctest-modules \
|
--doctest-modules \
|
||||||
{posargs:./httpie ./tests}
|
{posargs:./httpie ./tests}
|
||||||
|
|
||||||
[testenv:codestyle]
|
[testenv:py27-osx-builtin]
|
||||||
deps = pycodestyle
|
basepython = /usr/bin/python2.7
|
||||||
commands =
|
|
||||||
pycodestyle \
|
|
||||||
--ignore=E241,E501
|
|
||||||
# 241 - multiple spaces after ‘,’
|
|
||||||
# 501 - line too long
|
|
||||||
|
Reference in New Issue
Block a user