mirror of
https://github.com/httpie/cli.git
synced 2025-08-10 12:27:45 +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/
|
||||
__pycache__/
|
||||
dist/
|
||||
httpie.egg-info/
|
||||
build/
|
||||
*.egg-info
|
||||
.cache/
|
||||
.tox
|
||||
.tox/
|
||||
.coverage
|
||||
*.pyc
|
||||
*.egg
|
||||
htmlcov
|
||||
.pytest_cache/
|
||||
|
98
.travis.yml
98
.travis.yml
@ -1,94 +1,96 @@
|
||||
# https://travis-ci.org/jkbrzt/httpie
|
||||
# <https://travis-ci.org/jakubroztocil/httpie>
|
||||
sudo: false
|
||||
|
||||
language: python
|
||||
os:
|
||||
- linux
|
||||
|
||||
env:
|
||||
global:
|
||||
- NEWEST_PYTHON=3.5
|
||||
|
||||
- NEWEST_PYTHON=3.7
|
||||
python:
|
||||
- 2.6
|
||||
# <https://docs.travis-ci.com/user/languages/python/>
|
||||
|
||||
- 2.7
|
||||
- pypy
|
||||
- 3.4
|
||||
|
||||
# Python 3.4 fails installing packages
|
||||
# <https://travis-ci.org/jakubroztocil/httpie/jobs/403263566#L636>
|
||||
# - 3.4
|
||||
|
||||
- 3.5
|
||||
# Currently fails because of a Flask issue
|
||||
# - pypy3
|
||||
- 3.6
|
||||
# - 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:
|
||||
|
||||
include:
|
||||
|
||||
# Manually defined OS X builds
|
||||
# https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages)
|
||||
|
||||
# Add manually defined OS X builds
|
||||
# <https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages)>
|
||||
- os: osx
|
||||
language: generic
|
||||
env:
|
||||
# Stock OSX Python
|
||||
- TOXENV=py27-osx-builtin
|
||||
- BREW_PYTHON_PACKAGE=
|
||||
- os: osx
|
||||
language: generic
|
||||
env:
|
||||
# Latest Python 2.7 from Homebrew
|
||||
- TOXENV=py27
|
||||
|
||||
# Latest Python 2.x from Homebrew
|
||||
- BREW_PYTHON_PACKAGE=python@2
|
||||
- os: osx
|
||||
language: generic
|
||||
env:
|
||||
- TOXENV=py27
|
||||
- BREW_INSTALL=python
|
||||
|
||||
# Latest Python 3.x from Homebrew
|
||||
- os: osx
|
||||
language: generic
|
||||
env:
|
||||
- TOXENV=py35
|
||||
- BREW_INSTALL=python3
|
||||
|
||||
# Python Codestyle
|
||||
- TOXENV=py37 # <= needs to be kept up-to-date to reflect latest minor version
|
||||
- BREW_PYTHON_PACKAGE=python@3
|
||||
# Travis Python 3.7 must run sudo on
|
||||
- os: linux
|
||||
python: 3.5
|
||||
env: CODESTYLE=true
|
||||
|
||||
python: 3.7
|
||||
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:
|
||||
- |
|
||||
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
|
||||
if [[ -n "$BREW_INSTALL" ]]; then
|
||||
if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then
|
||||
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
|
||||
sudo pip install tox
|
||||
fi
|
||||
if [[ $CODESTYLE ]]; then
|
||||
pip install pycodestyle
|
||||
sudo pip2 install tox
|
||||
fi
|
||||
|
||||
script:
|
||||
- |
|
||||
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||
if [[ $CODESTYLE ]]; then
|
||||
# 241 - multiple spaces after ‘,’
|
||||
# 501 - line too long
|
||||
pycodestyle --ignore=E241,E501
|
||||
if [[ $CODESTYLE_ONLY ]]; then
|
||||
make pycodestyle
|
||||
else
|
||||
make
|
||||
make test
|
||||
fi
|
||||
else
|
||||
PATH="/usr/local/bin:$PATH" tox -e "$TOXENV"
|
||||
fi
|
||||
|
||||
after_success:
|
||||
- |
|
||||
if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||
pip install python-coveralls && coveralls
|
||||
make coveralls
|
||||
fi
|
||||
|
||||
notifications:
|
||||
|
||||
webhooks:
|
||||
# options: [always|never|change] default: always
|
||||
on_success: always
|
||||
on_failure: always
|
||||
on_start: always
|
||||
urls:
|
||||
# https://gitter.im/jkbrzt/httpie
|
||||
- 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
|
||||
==============
|
||||
|
||||
* `Jakub Roztocil <https://github.com/jkbrzt>`_
|
||||
* `Jakub Roztocil <https://github.com/jakubroztocil>`_
|
||||
|
||||
|
||||
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)
|
||||
* `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/>`_.
|
||||
|
||||
|
||||
`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)
|
||||
---------------------
|
||||
|
||||
@ -92,8 +109,8 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
|
||||
---------------------
|
||||
|
||||
* Added support for Requests transport adapter plugins
|
||||
(see `httpie-unixsocket <https://github.com/msabramo/httpie-unixsocket>`_
|
||||
and `httpie-http2 <https://github.com/jkbrzt/httpie-http2>`_)
|
||||
(see `httpie-unixsocket <https://github.com/httpie/httpie-unixsocket>`_
|
||||
and `httpie-http2 <https://github.com/httpie/httpie-http2>`_)
|
||||
|
||||
|
||||
`0.9.0`_ (2015-01-31)
|
||||
@ -297,29 +314,30 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
|
||||
* Initial public release
|
||||
|
||||
|
||||
.. _`0.1`: https://github.com/jkbrzt/httpie/commit/b966efa
|
||||
.. _0.1.4: https://github.com/jkbrzt/httpie/compare/b966efa...0.1.4
|
||||
.. _0.1.5: https://github.com/jkbrzt/httpie/compare/0.1.4...0.1.5
|
||||
.. _0.1.6: https://github.com/jkbrzt/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.1: https://github.com/jkbrzt/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.5: https://github.com/jkbrzt/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.7: https://github.com/jkbrzt/httpie/compare/0.2.5...0.2.7
|
||||
.. _0.3.0: https://github.com/jkbrzt/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.1: https://github.com/jkbrzt/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.1: https://github.com/jkbrzt/httpie/compare/0.5.0...0.5.1
|
||||
.. _0.6.0: https://github.com/jkbrzt/httpie/compare/0.5.1...0.6.0
|
||||
.. _0.7.1: https://github.com/jkbrzt/httpie/compare/0.6.0...0.7.1
|
||||
.. _0.8.0: https://github.com/jkbrzt/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.1: https://github.com/jkbrzt/httpie/compare/0.9.0...0.9.1
|
||||
.. _0.9.2: https://github.com/jkbrzt/httpie/compare/0.9.1...0.9.2
|
||||
.. _0.9.3: https://github.com/jkbrzt/httpie/compare/0.9.2...0.9.3
|
||||
.. _0.9.4: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.4
|
||||
.. _0.9.6: https://github.com/jkbrzt/httpie/compare/0.9.4...0.9.6
|
||||
.. _0.9.8: https://github.com/jkbrzt/httpie/compare/0.9.6...0.9.8
|
||||
.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.8...master
|
||||
.. _`0.1`: https://github.com/jakubroztocil/httpie/commit/b966efa
|
||||
.. _0.1.4: https://github.com/jakubroztocil/httpie/compare/b966efa...0.1.4
|
||||
.. _0.1.5: https://github.com/jakubroztocil/httpie/compare/0.1.4...0.1.5
|
||||
.. _0.1.6: https://github.com/jakubroztocil/httpie/compare/0.1.5...0.1.6
|
||||
.. _0.2.0: https://github.com/jakubroztocil/httpie/compare/0.1.6...0.2.0
|
||||
.. _0.2.1: https://github.com/jakubroztocil/httpie/compare/0.2.0...0.2.1
|
||||
.. _0.2.2: https://github.com/jakubroztocil/httpie/compare/0.2.1...0.2.2
|
||||
.. _0.2.5: https://github.com/jakubroztocil/httpie/compare/0.2.2...0.2.5
|
||||
.. _0.2.6: https://github.com/jakubroztocil/httpie/compare/0.2.5...0.2.6
|
||||
.. _0.2.7: https://github.com/jakubroztocil/httpie/compare/0.2.5...0.2.7
|
||||
.. _0.3.0: https://github.com/jakubroztocil/httpie/compare/0.2.7...0.3.0
|
||||
.. _0.4.0: https://github.com/jakubroztocil/httpie/compare/0.3.0...0.4.0
|
||||
.. _0.4.1: https://github.com/jakubroztocil/httpie/compare/0.4.0...0.4.1
|
||||
.. _0.5.0: https://github.com/jakubroztocil/httpie/compare/0.4.1...0.5.0
|
||||
.. _0.5.1: https://github.com/jakubroztocil/httpie/compare/0.5.0...0.5.1
|
||||
.. _0.6.0: https://github.com/jakubroztocil/httpie/compare/0.5.1...0.6.0
|
||||
.. _0.7.1: https://github.com/jakubroztocil/httpie/compare/0.6.0...0.7.1
|
||||
.. _0.8.0: https://github.com/jakubroztocil/httpie/compare/0.7.1...0.8.0
|
||||
.. _0.9.0: https://github.com/jakubroztocil/httpie/compare/0.8.0...0.9.0
|
||||
.. _0.9.1: https://github.com/jakubroztocil/httpie/compare/0.9.0...0.9.1
|
||||
.. _0.9.2: https://github.com/jakubroztocil/httpie/compare/0.9.1...0.9.2
|
||||
.. _0.9.3: https://github.com/jakubroztocil/httpie/compare/0.9.2...0.9.3
|
||||
.. _0.9.4: https://github.com/jakubroztocil/httpie/compare/0.9.3...0.9.4
|
||||
.. _0.9.6: https://github.com/jakubroztocil/httpie/compare/0.9.4...0.9.6
|
||||
.. _0.9.8: https://github.com/jakubroztocil/httpie/compare/0.9.6...0.9.8
|
||||
.. _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`_
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
@ -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
|
||||
# so that the `http' command will point to your working copy):
|
||||
make
|
||||
make init
|
||||
|
||||
|
||||
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
|
||||
@ -71,18 +72,18 @@ Running all tests:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Run all tests on the current Python interpreter
|
||||
# Run all tests on the current Python interpreter with coverage
|
||||
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
|
||||
make test-tox
|
||||
|
||||
# Run all tests for code as well as packaging, etc.
|
||||
make test-all
|
||||
|
||||
# Test PEP8 compliance
|
||||
make pycodestyle
|
||||
|
||||
|
||||
Running specific tests:
|
||||
***********************
|
||||
@ -95,11 +96,11 @@ Running specific tests:
|
||||
py.test tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok
|
||||
|
||||
# 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::TestMultipartFormDataFileUpload --verbose
|
||||
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok --verbose
|
||||
|
||||
|
||||
-----
|
||||
|
||||
See `Makefile`_ for additional development utilities.
|
||||
@ -107,10 +108,10 @@ Don't forget to add yourself to `AUTHORS`_!
|
||||
|
||||
|
||||
.. _Tox: http://tox.testrun.org
|
||||
.. _supported Python environments: https://github.com/jkbrzt/httpie/blob/master/tox.ini
|
||||
.. _existing issues: https://github.com/jkbrzt/httpie/issues?state=open
|
||||
.. _AUTHORS: https://github.com/jkbrzt/httpie/blob/master/AUTHORS.rst
|
||||
.. _Makefile: https://github.com/jkbrzt/httpie/blob/master/Makefile
|
||||
.. _supported Python environments: https://github.com/jakubroztocil/httpie/blob/master/tox.ini
|
||||
.. _existing issues: https://github.com/jakubroztocil/httpie/issues?state=open
|
||||
.. _AUTHORS: https://github.com/jakubroztocil/httpie/blob/master/AUTHORS.rst
|
||||
.. _Makefile: https://github.com/jakubroztocil/httpie/blob/master/Makefile
|
||||
.. _pytest: http://pytest.org/
|
||||
.. _Style Guide for Python Code: http://python.org/dev/peps/pep-0008/
|
||||
.. _test suite: https://github.com/jkbrzt/httpie/tree/master/tests
|
||||
.. _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
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
57
Makefile
57
Makefile
@ -1,6 +1,6 @@
|
||||
#
|
||||
###############################################################################
|
||||
# See ./CONTRIBUTING.rst
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
VERSION=$(shell grep __version__ httpie/__init__.py)
|
||||
REQUIREMENTS="requirements-dev.txt"
|
||||
@ -20,6 +20,17 @@ init: uninstall-httpie
|
||||
|
||||
@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
|
||||
@echo $(TAG)Running tests on the current Python interpreter with coverage $(END)
|
||||
@ -27,9 +38,8 @@ test: init
|
||||
@echo
|
||||
|
||||
|
||||
test-tox: init
|
||||
@echo $(TAG)Running tests on all Pythons via Tox$(END)
|
||||
tox
|
||||
# test-all is meant to test everything — even this Makefile
|
||||
test-all: uninstall-all clean init test test-tox test-dist pycodestyle
|
||||
@echo
|
||||
|
||||
|
||||
@ -37,6 +47,12 @@ test-dist: test-sdist test-bdist-wheel
|
||||
@echo
|
||||
|
||||
|
||||
test-tox: init
|
||||
@echo $(TAG)Running tests on all Pythons via Tox$(END)
|
||||
tox
|
||||
@echo
|
||||
|
||||
|
||||
test-sdist: clean uninstall-httpie
|
||||
@echo $(TAG)Testing sdist build an installation$(END)
|
||||
python setup.py sdist
|
||||
@ -53,12 +69,26 @@ test-bdist-wheel: clean uninstall-httpie
|
||||
@echo
|
||||
|
||||
|
||||
# This tests everything, even this Makefile.
|
||||
test-all: uninstall-all clean init test test-tox test-dist
|
||||
pycodestyle:
|
||||
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-no-test:
|
||||
@echo $(TAG)Testing wheel build an installation$(END)
|
||||
@echo "$(VERSION)"
|
||||
@ -69,12 +99,10 @@ publish-no-test:
|
||||
@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:
|
||||
@echo $(TAG)Uninstalling httpie$(END)
|
||||
@ -96,5 +124,10 @@ uninstall-all: uninstall-httpie
|
||||
- pip uninstall --yes -r $(REQUIREMENTS)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Utils
|
||||
###############################################################################
|
||||
|
||||
|
||||
homebrew-formula-vars:
|
||||
extras/get-homebrew-formula-vars.py
|
||||
|
215
README.rst
215
README.rst
@ -11,7 +11,7 @@ generally interacting with HTTP servers.
|
||||
|
||||
.. 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
|
||||
:width: 100%
|
||||
:align: center
|
||||
@ -19,7 +19,7 @@ generally interacting with HTTP servers.
|
||||
|
||||
.. 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::
|
||||
|
||||
.. raw:: pdf
|
||||
|
||||
PageBreak oneColumn
|
||||
|
||||
|
||||
Main features
|
||||
@ -44,8 +41,8 @@ Main features
|
||||
* Custom headers
|
||||
* Persistent sessions
|
||||
* Wget-like downloads
|
||||
* Python 2.6, 2.7 and 3.x support
|
||||
* Linux, Mac OS X and Windows support
|
||||
* Python 2.7 and 3.x support
|
||||
* Linux, macOS and Windows support
|
||||
* Plugins
|
||||
* Documentation
|
||||
* Test coverage
|
||||
@ -77,16 +74,25 @@ Linux
|
||||
-----
|
||||
|
||||
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
|
||||
|
||||
# Debian-based distributions such as Ubuntu:
|
||||
# Debian, Ubuntu, etc.
|
||||
$ apt-get install httpie
|
||||
|
||||
# RPM-based distributions:
|
||||
.. code-block:: bash
|
||||
|
||||
# Fedora
|
||||
$ dnf install httpie
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# CentOS, RHEL, ...
|
||||
$ yum install httpie
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Arch Linux
|
||||
$ pacman -S httpie
|
||||
|
||||
@ -110,31 +116,51 @@ and always provides the latest version) is to use `pip`_:
|
||||
``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
|
||||
--------------
|
||||
|
||||
Although Python 2.6 and 2.7 are supported as well, it is recommended to install
|
||||
HTTPie against the latest Python 3.x whenever possible. That will ensure that
|
||||
some of the newer HTTP features, such as `SNI (Server Name Indication)`_,
|
||||
work out of the box.
|
||||
Although Python 2.7 is supported as well, it is strongly recommended to
|
||||
install HTTPie against the latest Python 3.x whenever possible. That will
|
||||
ensure that some of the newer HTTP features, such as
|
||||
`SNI (Server Name Indication)`_, work out of the box.
|
||||
Python 3 is the default for Homebrew installations starting with version 0.9.4.
|
||||
To see which version HTTPie uses, run ``http --debug``.
|
||||
|
||||
|
||||
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
|
||||
=====
|
||||
|
||||
@ -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
|
||||
`issue <https://github.com/jkbrzt/httpie/issues/83>`_
|
||||
`issue <https://github.com/jakubroztocil/httpie/issues/83>`_
|
||||
with `authentication`_:
|
||||
|
||||
.. 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`_:
|
||||
@ -261,7 +287,7 @@ and can be omitted from the argument – ``http example.org`` works just fine.
|
||||
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
|
||||
URL parameters. With that, you don't have to worry about escaping the ``&``
|
||||
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:
|
||||
`Redirected input`_ is a mechanism for passing arbitrary data request
|
||||
request.
|
||||
`Redirected input`_ is a mechanism for passing arbitrary request data.
|
||||
|
||||
|
||||
Escaping rules
|
||||
@ -400,7 +425,7 @@ token ``--`` to prevent confusion with ``--arguments``:
|
||||
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
|
||||
**implicit content type** HTTPie by default uses.
|
||||
**implicit content type** HTTPie uses by default.
|
||||
|
||||
|
||||
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;'
|
||||
|
||||
|
||||
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
|
||||
==============
|
||||
|
||||
@ -670,7 +742,7 @@ Password prompt
|
||||
``.netrc``
|
||||
----------
|
||||
|
||||
Authorization information from your ``~/.netrc`` file is honored as well:
|
||||
Authentication information from your ``~/.netrc`` file is honored as well:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -791,7 +863,7 @@ In your ``~/.bash_profile``:
|
||||
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
|
||||
@ -855,7 +927,7 @@ SSL version
|
||||
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
|
||||
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.)
|
||||
|
||||
.. code-block:: bash
|
||||
@ -895,7 +967,7 @@ be printed via several options:
|
||||
``--headers, -h`` Only the response headers are printed.
|
||||
``--body, -b`` Only the response body is printed.
|
||||
``--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.
|
||||
================= =====================================================
|
||||
|
||||
@ -1035,7 +1107,7 @@ You can even pipe web services together using HTTPie:
|
||||
|
||||
.. 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:
|
||||
@ -1212,7 +1284,7 @@ is being saved to a file.
|
||||
|
||||
.. 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
|
||||
|
||||
@ -1242,7 +1314,7 @@ headers and progress are still shown in the terminal:
|
||||
|
||||
.. 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
|
||||
sessions via the ``--session=SESSION_NAME_OR_PATH`` option. In a session,
|
||||
custom headers—except for the ones starting with ``Content-`` or ``If-``—,
|
||||
authorization, and cookies
|
||||
custom `HTTP headers`_ (except for the ones starting with ``Content-`` or ``If-``),
|
||||
`authentication`_, and `cookies`_
|
||||
(manually specified or sent by the server) persist between requests
|
||||
to the same host.
|
||||
|
||||
@ -1335,11 +1407,12 @@ to the same host.
|
||||
$ http --session=/tmp/session.json example.org
|
||||
|
||||
|
||||
|
||||
All session data, including credentials, cookie data,
|
||||
and custom headers are stored in plain 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
|
||||
--------------
|
||||
@ -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
|
||||
|
||||
From now onw, 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
|
||||
From now on, you can refer to the session by its name. When you choose to
|
||||
use the session again, any previously specified authentication or HTTP headers
|
||||
will automatically be set:
|
||||
|
||||
.. 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
|
||||
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.
|
||||
|
||||
|
||||
@ -1555,7 +1628,7 @@ Please use the following support channels:
|
||||
to ask questions (please make sure to use the
|
||||
`httpie <http://stackoverflow.com/questions/tagged/httpie>`_ tag).
|
||||
* Tweet directly to `@clihttp <https://twitter.com/clihttp>`_.
|
||||
* You can also tweet directly to `@jkbrzt`_.
|
||||
* You can also tweet directly to `@jakubroztocil`_.
|
||||
|
||||
|
||||
Related projects
|
||||
@ -1585,16 +1658,25 @@ HTTPie plays exceptionally well with the following tools:
|
||||
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
|
||||
------------
|
||||
|
||||
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
|
||||
----------
|
||||
|
||||
See `CHANGELOG <https://github.com/jkbrzt/httpie/blob/master/CHANGELOG.rst>`_.
|
||||
See `CHANGELOG <https://github.com/jakubroztocil/httpie/blob/master/CHANGELOG.rst>`_.
|
||||
|
||||
|
||||
Artwork
|
||||
@ -1606,22 +1688,22 @@ See `claudiatd/httpie-artwork`_
|
||||
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
|
||||
-------
|
||||
|
||||
`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_
|
||||
`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_
|
||||
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
|
||||
.. _these fine people: https://github.com/jkbrzt/httpie/contributors
|
||||
.. _Jakub Roztocil: http://roztocil.co
|
||||
.. _@jkbrzt: https://twitter.com/jkbrzt
|
||||
.. _these fine people: https://github.com/jakubroztocil/httpie/contributors
|
||||
.. _Jakub Roztocil: https://roztocil.co
|
||||
.. _@jakubroztocil: https://twitter.com/jakubroztocil
|
||||
.. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork
|
||||
|
||||
|
||||
@ -1629,19 +1711,14 @@ have contributed.
|
||||
:target: https://pypi.python.org/pypi/httpie
|
||||
:alt: Latest version released on PyPi
|
||||
|
||||
.. |coverage| image:: https://img.shields.io/coveralls/jkbrzt/httpie/master.svg?style=flat-square&label=coverage
|
||||
:target: https://coveralls.io/r/jkbrzt/httpie?branch=master
|
||||
.. |coverage| image:: https://img.shields.io/coveralls/jakubroztocil/httpie/master.svg?style=flat-square&label=coverage
|
||||
:target: https://coveralls.io/r/jakubroztocil/httpie?branch=master
|
||||
:alt: Test coverage
|
||||
|
||||
.. |unix_build| image:: https://img.shields.io/travis/jkbrzt/httpie/master.svg?style=flat-square&label=unix%20build
|
||||
:target: http://travis-ci.org/jkbrzt/httpie
|
||||
.. |unix_build| image:: https://img.shields.io/travis/jakubroztocil/httpie/master.svg?style=flat-square&label=unix%20build
|
||||
:target: http://travis-ci.org/jakubroztocil/httpie
|
||||
: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
|
||||
: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
|
||||
.. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square
|
||||
:target: https://gitter.im/jkbrzt/httpie
|
||||
: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
|
||||
"""
|
||||
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
|
||||
|
||||
@ -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)
|
||||
resp = requests.get(api_url).json()
|
||||
hasher = hashlib.sha256()
|
||||
@ -35,21 +35,23 @@ def get_info(package_name):
|
||||
'{}: download not found: {}'.format(package_name, resp))
|
||||
|
||||
|
||||
packages = {
|
||||
package_name: get_info(package_name) for package_name in PACKAGES
|
||||
}
|
||||
def main():
|
||||
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')
|
||||
print("""
|
||||
url "{url}"
|
||||
sha256 "{sha256}"
|
||||
""".format(**httpie_info))
|
||||
|
||||
|
||||
for package_info in packages.values():
|
||||
print("""
|
||||
resource "{name}" do
|
||||
url "{url}"
|
||||
sha256 "{sha256}"
|
||||
end""".format(**package_info))
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -30,11 +30,10 @@ function __fish_httpie_styles
|
||||
echo "xcode"
|
||||
end
|
||||
|
||||
complete -x -c http -s s -l style -d 'Output coloring style (default is "monokai")' -A -a "autumn borland bw colorful default emacs friendly fruity igor manni monokai murphy native paraiso-dark paraiso-light pastie perldoc rrt solarized tango trac vim vs xcode"
|
||||
complete -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 j -l json -d '(default) Data items from the command line are serialized as a JSON object'
|
||||
complete -x -c http -l pretty -d 'Controls output processing' -a "all colors format none" -A
|
||||
complete -x -c http -s s -l style -d 'Output coloring style (default is "monokai")' -A -a "autumn borland bw colorful default emacs friendly fruity igor manni monokai murphy native paraiso-dark paraiso-light pastie perldoc rrt solarized tango trac vim vs xcode"
|
||||
complete -x -c http -s p -l print -d 'String specifying what the output should contain'
|
||||
complete -c http -s v -l verbose -d 'Print the whole request as well as the response'
|
||||
complete -c http -s h -l headers -d 'Print only the response headers'
|
||||
|
@ -11,7 +11,7 @@ class Httpie < Formula
|
||||
url "https://pypi.python.org/packages/85/95/7ccea3ae7fd1185e21629f6d14fa9c896d6250bb15fb492efa91edc741a2/httpie-0.9.8.tar.gz"
|
||||
sha256 "515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1"
|
||||
|
||||
head "https://github.com/jkbrzt/httpie.git"
|
||||
head "https://github.com/jakubroztocil/httpie.git"
|
||||
|
||||
depends_on :python3
|
||||
|
||||
|
@ -2,14 +2,14 @@
|
||||
HTTPie - a CLI, cURL-like tool for humans.
|
||||
|
||||
"""
|
||||
__version__ = '1.0.0'
|
||||
__author__ = 'Jakub Roztocil'
|
||||
__version__ = '0.9.8'
|
||||
__licence__ = 'BSD'
|
||||
|
||||
|
||||
class ExitStatus:
|
||||
"""Exit status code constants."""
|
||||
OK = 0
|
||||
"""Program exit code constants."""
|
||||
SUCCESS = 0
|
||||
ERROR = 1
|
||||
PLUGIN_ERROR = 7
|
||||
|
||||
@ -25,8 +25,8 @@ class ExitStatus:
|
||||
ERROR_HTTP_5XX = 5
|
||||
|
||||
|
||||
EXIT_STATUS_LABELS = dict(
|
||||
(value, key)
|
||||
EXIT_STATUS_LABELS = {
|
||||
value: key
|
||||
for key, value in ExitStatus.__dict__.items()
|
||||
if key.isupper()
|
||||
)
|
||||
}
|
||||
|
@ -20,7 +20,9 @@ from httpie.input import (
|
||||
PRETTY_STDOUT_TTY_ONLY, SessionNameValidator,
|
||||
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.builtin import BuiltinAuthPlugin
|
||||
from httpie.sessions import DEFAULT_SESSIONS_DIR
|
||||
@ -46,6 +48,7 @@ class HTTPieHelpFormatter(RawDescriptionHelpFormatter):
|
||||
|
||||
|
||||
parser = HTTPieArgumentParser(
|
||||
prog='http',
|
||||
formatter_class=HTTPieHelpFormatter,
|
||||
description='%s <http://httpie.org>' % __doc__.strip(),
|
||||
epilog=dedent("""
|
||||
@ -54,7 +57,7 @@ parser = HTTPieArgumentParser(
|
||||
|
||||
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="""
|
||||
Output coloring style (default is "{default}"). One of:
|
||||
|
||||
{available}
|
||||
{available_styles}
|
||||
|
||||
For this option to work properly, please make sure that the $TERM
|
||||
environment variable is set to "xterm-256color" or similar
|
||||
The "{auto_style}" style follows your terminal's ANSI color styles.
|
||||
|
||||
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).
|
||||
|
||||
""".format(
|
||||
default=DEFAULT_STYLE,
|
||||
available='\n'.join(
|
||||
available_styles='\n'.join(
|
||||
'{0}{1}'.format(8 * ' ', line.strip())
|
||||
for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60)
|
||||
).rstrip(),
|
||||
auto_style=AUTO_STYLE,
|
||||
)
|
||||
)
|
||||
|
||||
@ -544,10 +550,10 @@ ssl.add_argument(
|
||||
'--verify',
|
||||
default='yes',
|
||||
help="""
|
||||
Set to "no" to skip checking the host's SSL certificate. You can also pass
|
||||
the path to a CA_BUNDLE file for private certs. You can also set the
|
||||
REQUESTS_CA_BUNDLE environment variable. Defaults to "yes".
|
||||
|
||||
Set to "no" (or "false") to skip checking the host's SSL certificate.
|
||||
Defaults to "yes" ("true"). You can also pass the path to a CA_BUNDLE file
|
||||
for private certs. (Or you can set the REQUESTS_CA_BUNDLE environment
|
||||
variable instead.)
|
||||
"""
|
||||
)
|
||||
ssl.add_argument(
|
||||
|
@ -3,7 +3,7 @@ import sys
|
||||
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
from requests.packages import urllib3
|
||||
from requests.structures import CaseInsensitiveDict
|
||||
|
||||
from httpie import sessions
|
||||
from httpie import __version__
|
||||
@ -14,8 +14,10 @@ from httpie.utils import repr_dict_nice
|
||||
|
||||
try:
|
||||
# https://urllib3.readthedocs.io/en/latest/security.html
|
||||
# noinspection PyPackageRequirements
|
||||
import urllib3
|
||||
urllib3.disable_warnings()
|
||||
except AttributeError:
|
||||
except (ImportError, AttributeError):
|
||||
# In some rare cases, the user may have an old version of the requests
|
||||
# or urllib3, and there is no method called "disable_warnings." In these
|
||||
# cases, we don't need to call the method.
|
||||
@ -97,7 +99,7 @@ def finalize_headers(headers):
|
||||
value = value.strip()
|
||||
|
||||
if isinstance(value, str):
|
||||
# See: https://github.com/jkbrzt/httpie/issues/212
|
||||
# See: https://github.com/jakubroztocil/httpie/issues/212
|
||||
value = value.encode('utf8')
|
||||
|
||||
final_headers[name] = value
|
||||
@ -105,9 +107,9 @@ def finalize_headers(headers):
|
||||
|
||||
|
||||
def get_default_headers(args):
|
||||
default_headers = {
|
||||
default_headers = CaseInsensitiveDict({
|
||||
'User-Agent': DEFAULT_UA
|
||||
}
|
||||
})
|
||||
|
||||
auto_json = args.data and not args.form
|
||||
if args.json or auto_json:
|
||||
@ -159,12 +161,14 @@ def get_requests_kwargs(args, base_headers=None):
|
||||
'data': data,
|
||||
'verify': {
|
||||
'yes': True,
|
||||
'no': False
|
||||
}.get(args.verify, args.verify),
|
||||
'true': True,
|
||||
'no': False,
|
||||
'false': False,
|
||||
}.get(args.verify.lower(), args.verify),
|
||||
'cert': cert,
|
||||
'timeout': args.timeout,
|
||||
'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,
|
||||
'allow_redirects': args.follow,
|
||||
'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
|
||||
|
||||
|
||||
is_py2 = sys.version_info[0] == 2
|
||||
is_py26 = sys.version_info[:2] == (2, 6)
|
||||
is_py27 = sys.version_info[:2] == (2, 7)
|
||||
is_py3 = sys.version_info[0] == 3
|
||||
is_pypy = 'pypy' in sys.version.lower()
|
||||
@ -38,141 +37,3 @@ try: # pragma: no cover
|
||||
except ImportError: # pragma: no cover
|
||||
# noinspection PyCompatibility,PyUnresolvedReferences
|
||||
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):
|
||||
|
||||
name = 'config'
|
||||
helpurl = 'https://httpie.org/docs#config'
|
||||
helpurl = 'https://httpie.org/doc#config'
|
||||
about = 'HTTPie configuration file'
|
||||
|
||||
DEFAULTS = {
|
||||
@ -104,7 +104,7 @@ class Config(BaseConfigDict):
|
||||
try:
|
||||
implicit_content_type = self.pop('implicit_content_type')
|
||||
except KeyError:
|
||||
pass
|
||||
self.save()
|
||||
else:
|
||||
if implicit_content_type == 'form':
|
||||
self['default_options'].insert(0, '--form')
|
||||
|
@ -43,7 +43,7 @@ def get_exit_status(http_status, follow=False):
|
||||
# Server Error
|
||||
return ExitStatus.ERROR_HTTP_5XX
|
||||
else:
|
||||
return ExitStatus.OK
|
||||
return ExitStatus.SUCCESS
|
||||
|
||||
|
||||
def print_debug_info(env):
|
||||
@ -61,7 +61,7 @@ def print_debug_info(env):
|
||||
|
||||
def decode_args(args, stdin_encoding):
|
||||
"""
|
||||
Convert all bytes ags to str
|
||||
Convert all bytes args to str
|
||||
by decoding them using stdin encoding.
|
||||
|
||||
"""
|
||||
@ -82,7 +82,7 @@ def program(args, env, log_error):
|
||||
:return: status code
|
||||
|
||||
"""
|
||||
exit_status = ExitStatus.OK
|
||||
exit_status = ExitStatus.SUCCESS
|
||||
downloader = None
|
||||
show_traceback = args.debug or args.traceback
|
||||
|
||||
@ -109,7 +109,7 @@ def program(args, env, log_error):
|
||||
http_status=response.status_code,
|
||||
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(
|
||||
'HTTP %s %s', response.raw.status, response.raw.reason,
|
||||
level='warning'
|
||||
@ -143,7 +143,7 @@ def program(args, env, log_error):
|
||||
else:
|
||||
raise
|
||||
|
||||
if downloader and exit_status == ExitStatus.OK:
|
||||
if downloader and exit_status == ExitStatus.SUCCESS:
|
||||
# Last response body download.
|
||||
download_stream, download_to = downloader.start(final_response)
|
||||
write_stream(
|
||||
@ -164,8 +164,8 @@ def program(args, env, log_error):
|
||||
if downloader and not downloader.finished:
|
||||
downloader.failed()
|
||||
|
||||
if (not isinstance(args, list) and args.output_file and
|
||||
args.output_file_specified):
|
||||
if (not isinstance(args, list) and args.output_file
|
||||
and args.output_file_specified):
|
||||
args.output_file.close()
|
||||
|
||||
|
||||
@ -202,9 +202,9 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None):
|
||||
if include_debug_info:
|
||||
print_debug_info(env)
|
||||
if args == ['--debug']:
|
||||
return ExitStatus.OK
|
||||
return ExitStatus.SUCCESS
|
||||
|
||||
exit_status = ExitStatus.OK
|
||||
exit_status = ExitStatus.SUCCESS
|
||||
|
||||
try:
|
||||
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
|
||||
exit_status = ExitStatus.ERROR_CTRL_C
|
||||
except SystemExit as e:
|
||||
if e.code != ExitStatus.OK:
|
||||
if e.code != ExitStatus.SUCCESS:
|
||||
env.stderr.write('\n')
|
||||
if include_traceback:
|
||||
raise
|
||||
@ -232,7 +232,7 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None):
|
||||
raise
|
||||
exit_status = ExitStatus.ERROR_CTRL_C
|
||||
except SystemExit as e:
|
||||
if e.code != ExitStatus.OK:
|
||||
if e.code != ExitStatus.SUCCESS:
|
||||
env.stderr.write('\n')
|
||||
if include_traceback:
|
||||
raise
|
||||
|
@ -54,8 +54,8 @@ def parse_content_range(content_range, resumed_from):
|
||||
raise ContentRangeError('Missing Content-Range')
|
||||
|
||||
pattern = (
|
||||
'^bytes (?P<first_byte_pos>\d+)-(?P<last_byte_pos>\d+)'
|
||||
'/(\*|(?P<instance_length>\d+))$'
|
||||
r'^bytes (?P<first_byte_pos>\d+)-(?P<last_byte_pos>\d+)'
|
||||
r'/(\*|(?P<instance_length>\d+))$'
|
||||
)
|
||||
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
|
||||
# byte-content-range- spec MUST ignore it and any content
|
||||
# transferred along with it."
|
||||
if (first_byte_pos >= last_byte_pos or
|
||||
(instance_length is not None and
|
||||
instance_length <= last_byte_pos)):
|
||||
if (first_byte_pos >= last_byte_pos
|
||||
or (instance_length is not None
|
||||
and instance_length <= last_byte_pos)):
|
||||
raise ContentRangeError(
|
||||
'Invalid Content-Range returned: %r' % content_range)
|
||||
|
||||
if (first_byte_pos != resumed_from or
|
||||
(instance_length is not None and
|
||||
last_byte_pos + 1 != instance_length)):
|
||||
if (first_byte_pos != resumed_from
|
||||
or (instance_length is not None
|
||||
and last_byte_pos + 1 != instance_length)):
|
||||
# Not what we asked for.
|
||||
raise ContentRangeError(
|
||||
'Unexpected Content-Range returned (%r)'
|
||||
@ -105,7 +105,7 @@ def filename_from_content_disposition(content_disposition):
|
||||
: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)
|
||||
filename = msg.get_filename()
|
||||
@ -238,7 +238,7 @@ class Downloader(object):
|
||||
assert not self.status.time_started
|
||||
|
||||
# FIXME: some servers still might sent Content-Encoding: gzip
|
||||
# <https://github.com/jkbrzt/httpie/issues/423>
|
||||
# <https://github.com/jakubroztocil/httpie/issues/423>
|
||||
try:
|
||||
total_size = int(response.headers['Content-Length'])
|
||||
except (KeyError, ValueError, TypeError):
|
||||
@ -308,9 +308,9 @@ class Downloader(object):
|
||||
@property
|
||||
def interrupted(self):
|
||||
return (
|
||||
self.finished and
|
||||
self.status.total_size and
|
||||
self.status.total_size != self.status.downloaded
|
||||
self.finished
|
||||
and self.status.total_size
|
||||
and self.status.total_size != self.status.downloaded
|
||||
)
|
||||
|
||||
def chunk_downloaded(self, chunk):
|
||||
@ -399,8 +399,8 @@ class ProgressReporterThread(threading.Thread):
|
||||
if now - self._prev_time >= self._update_interval:
|
||||
downloaded = self.status.downloaded
|
||||
try:
|
||||
speed = ((downloaded - self._prev_bytes) /
|
||||
(now - self._prev_time))
|
||||
speed = ((downloaded - self._prev_bytes)
|
||||
/ (now - self._prev_time))
|
||||
except ZeroDivisionError:
|
||||
speed = 0
|
||||
|
||||
@ -434,11 +434,11 @@ class ProgressReporterThread(threading.Thread):
|
||||
self._prev_bytes = downloaded
|
||||
|
||||
self.output.write(
|
||||
CLEAR_LINE +
|
||||
' ' +
|
||||
SPINNER[self._spinner_pos] +
|
||||
' ' +
|
||||
self._status_line
|
||||
CLEAR_LINE
|
||||
+ ' '
|
||||
+ SPINNER[self._spinner_pos]
|
||||
+ ' '
|
||||
+ self._status_line
|
||||
)
|
||||
self.output.flush()
|
||||
|
||||
@ -463,8 +463,8 @@ class ProgressReporterThread(threading.Thread):
|
||||
|
||||
self.output.write(SUMMARY.format(
|
||||
downloaded=humanize_bytes(actually_downloaded),
|
||||
total=(self.status.total_size and
|
||||
humanize_bytes(self.status.total_size)),
|
||||
total=(self.status.total_size
|
||||
and humanize_bytes(self.status.total_size)),
|
||||
speed=humanize_bytes(speed),
|
||||
time=time_taken,
|
||||
))
|
||||
|
@ -9,16 +9,16 @@ import errno
|
||||
import mimetypes
|
||||
import getpass
|
||||
from io import BytesIO
|
||||
from collections import namedtuple, Iterable
|
||||
from collections import namedtuple, Iterable, OrderedDict
|
||||
# noinspection PyCompatibility
|
||||
from argparse import ArgumentParser, ArgumentTypeError, ArgumentError
|
||||
|
||||
# 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 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.utils import load_json_preserve_order
|
||||
|
||||
@ -111,12 +111,13 @@ SSL_VERSION_ARG_MAPPING = {
|
||||
'tls1': 'PROTOCOL_TLSv1',
|
||||
'tls1.1': 'PROTOCOL_TLSv1_1',
|
||||
'tls1.2': 'PROTOCOL_TLSv1_2',
|
||||
'tls1.3': 'PROTOCOL_TLSv1_3',
|
||||
}
|
||||
SSL_VERSION_ARG_MAPPING = dict(
|
||||
(cli_arg, getattr(ssl, ssl_constant))
|
||||
SSL_VERSION_ARG_MAPPING = {
|
||||
cli_arg: getattr(ssl, ssl_constant)
|
||||
for cli_arg, ssl_constant in SSL_VERSION_ARG_MAPPING.items()
|
||||
if hasattr(ssl, ssl_constant)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class HTTPieArgumentParser(ArgumentParser):
|
||||
@ -254,8 +255,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
||||
else:
|
||||
credentials = parse_auth(self.args.auth)
|
||||
|
||||
if (not credentials.has_password() and
|
||||
plugin.prompt_password):
|
||||
if (not credentials.has_password()
|
||||
and plugin.prompt_password):
|
||||
if self.args.ignore_stdin:
|
||||
# Non-tty stdin read by now
|
||||
self.error(
|
||||
@ -302,7 +303,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
||||
"""
|
||||
if self.args.data:
|
||||
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()
|
||||
|
||||
def _guess_method(self):
|
||||
@ -337,10 +339,11 @@ class HTTPieArgumentParser(ArgumentParser):
|
||||
self.args.url = self.args.method
|
||||
# Infer the method
|
||||
has_data = (
|
||||
(not self.args.ignore_stdin and
|
||||
not self.env.stdin_isatty) or
|
||||
any(item.sep in SEP_GROUP_DATA_ITEMS
|
||||
for item in self.args.items)
|
||||
(not self.args.ignore_stdin and not self.env.stdin_isatty)
|
||||
or any(
|
||||
item.sep in SEP_GROUP_DATA_ITEMS
|
||||
for item in self.args.items
|
||||
)
|
||||
)
|
||||
self.args.method = HTTP_POST if has_data else HTTP_GET
|
||||
|
||||
@ -425,8 +428,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
||||
if self.args.prettify == PRETTY_STDOUT_TTY_ONLY:
|
||||
self.args.prettify = PRETTY_MAP[
|
||||
'all' if self.env.stdout_isatty else 'none']
|
||||
elif (self.args.prettify and self.env.is_windows and
|
||||
self.args.output_file):
|
||||
elif (self.args.prettify and self.env.is_windows
|
||||
and self.args.output_file):
|
||||
self.error('Only terminal output can be colorized on Windows.')
|
||||
else:
|
||||
# noinspection PyTypeChecker
|
||||
@ -468,8 +471,8 @@ class SessionNameValidator(object):
|
||||
|
||||
def __call__(self, value):
|
||||
# Session name can be a path or just a name.
|
||||
if (os.path.sep not in value and
|
||||
not VALID_SESSION_NAME_PATTERN.search(value)):
|
||||
if (os.path.sep not in value
|
||||
and not VALID_SESSION_NAME_PATTERN.search(value)):
|
||||
raise ArgumentError(None, self.error_message)
|
||||
return value
|
||||
|
||||
@ -504,7 +507,7 @@ class KeyValueArgType(object):
|
||||
"""Represents an escaped character."""
|
||||
|
||||
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:
|
||||
|
||||
tokenize(r'foo\=bar\\baz')
|
||||
|
@ -9,21 +9,25 @@ import pygments.style
|
||||
from pygments.formatters.terminal import TerminalFormatter
|
||||
from pygments.formatters.terminal256 import Terminal256Formatter
|
||||
from pygments.lexers.special import TextLexer
|
||||
from pygments.lexers.text import HttpLexer as PygmentsHttpLexer
|
||||
from pygments.util import ClassNotFound
|
||||
|
||||
from httpie.compat import is_windows
|
||||
from httpie.plugins import FormatterPlugin
|
||||
|
||||
|
||||
AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys())
|
||||
AVAILABLE_STYLES.add('solarized')
|
||||
|
||||
AUTO_STYLE = 'auto' # Follows terminal ANSI color styles
|
||||
DEFAULT_STYLE = AUTO_STYLE
|
||||
SOLARIZED_STYLE = 'solarized' # Bundled here
|
||||
if is_windows:
|
||||
# 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'
|
||||
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):
|
||||
@ -39,40 +43,56 @@ class ColorFormatter(FormatterPlugin):
|
||||
def __init__(self, env, explicit_json=False,
|
||||
color_scheme=DEFAULT_STYLE, **kwargs):
|
||||
super(ColorFormatter, self).__init__(**kwargs)
|
||||
|
||||
if not env.colors:
|
||||
self.enabled = False
|
||||
return
|
||||
|
||||
# --json, -j
|
||||
self.explicit_json = explicit_json
|
||||
|
||||
try:
|
||||
style_class = pygments.styles.get_style_by_name(color_scheme)
|
||||
except ClassNotFound:
|
||||
style_class = Solarized256Style
|
||||
|
||||
if env.colors == 256:
|
||||
fmt_class = Terminal256Formatter
|
||||
use_auto_style = color_scheme == AUTO_STYLE
|
||||
has_256_colors = env.colors == 256
|
||||
if use_auto_style or not has_256_colors:
|
||||
http_lexer = PygmentsHttpLexer()
|
||||
formatter = TerminalFormatter()
|
||||
else:
|
||||
fmt_class = TerminalFormatter
|
||||
self.formatter = fmt_class(style=style_class)
|
||||
http_lexer = SimplifiedHTTPLexer()
|
||||
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):
|
||||
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):
|
||||
lexer = self.get_lexer(mime, body)
|
||||
lexer = self.get_lexer_for_body(mime, body)
|
||||
if lexer:
|
||||
body = pygments.highlight(body, lexer, self.formatter)
|
||||
body = pygments.highlight(
|
||||
code=body,
|
||||
lexer=lexer,
|
||||
formatter=self.formatter,
|
||||
)
|
||||
return body.strip()
|
||||
|
||||
def get_lexer(self, mime, body):
|
||||
def get_lexer_for_body(self, mime, body):
|
||||
return get_lexer(
|
||||
mime=mime,
|
||||
explicit_json=self.explicit_json,
|
||||
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=''):
|
||||
|
||||
@ -121,7 +141,7 @@ def get_lexer(mime, explicit_json=False, body=''):
|
||||
return lexer
|
||||
|
||||
|
||||
class HTTPLexer(pygments.lexer.RegexLexer):
|
||||
class SimplifiedHTTPLexer(pygments.lexer.RegexLexer):
|
||||
"""Simplified HTTP lexer for Pygments.
|
||||
|
||||
It only operates on headers and provides a stronger contrast between
|
||||
|
@ -15,8 +15,8 @@ class JSONFormatter(FormatterPlugin):
|
||||
'javascript',
|
||||
'text',
|
||||
]
|
||||
if (self.kwargs['explicit_json'] or
|
||||
any(token in mime for token in maybe_json)):
|
||||
if (self.kwargs['explicit_json']
|
||||
or any(token in mime for token in maybe_json)):
|
||||
try:
|
||||
obj = json.loads(body)
|
||||
except ValueError:
|
||||
|
@ -15,7 +15,7 @@ class AuthPlugin(BasePlugin):
|
||||
"""
|
||||
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`
|
||||
|
||||
|
@ -17,7 +17,7 @@ class HTTPBasicAuth(requests.auth.HTTPBasicAuth):
|
||||
"""
|
||||
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(
|
||||
|
@ -39,8 +39,7 @@ class PluginManager(object):
|
||||
return [plugin for plugin in self if issubclass(plugin, AuthPlugin)]
|
||||
|
||||
def get_auth_plugin_mapping(self):
|
||||
return dict((plugin.auth_type, plugin)
|
||||
for plugin in self.get_auth_plugins())
|
||||
return {plugin.auth_type: plugin for plugin in self.get_auth_plugins()}
|
||||
|
||||
def get_auth_plugin(self, 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:
|
||||
path = os.path.expanduser(session_name)
|
||||
else:
|
||||
hostname = (args.headers.get('Host', None) or
|
||||
urlsplit(args.url).netloc.split('@')[-1])
|
||||
hostname = (args.headers.get('Host', None)
|
||||
or urlsplit(args.url).netloc.split('@')[-1])
|
||||
if not hostname:
|
||||
# HACK/FIXME: httpie-unixsocket's URLs have no hostname.
|
||||
hostname = 'localhost'
|
||||
@ -74,7 +74,7 @@ def get_response(requests_session, session_name,
|
||||
|
||||
|
||||
class Session(BaseConfigDict):
|
||||
helpurl = 'https://httpie.org/docs#sessions'
|
||||
helpurl = 'https://httpie.org/doc#sessions'
|
||||
about = 'HTTPie session file'
|
||||
|
||||
def __init__(self, path, *args, **kwargs):
|
||||
@ -136,10 +136,10 @@ class Session(BaseConfigDict):
|
||||
stored_attrs = ['value', 'path', 'secure', 'expires']
|
||||
self['cookies'] = {}
|
||||
for cookie in jar:
|
||||
self['cookies'][cookie.name] = dict(
|
||||
(attname, getattr(cookie, attname))
|
||||
self['cookies'][cookie.name] = {
|
||||
attname: getattr(cookie, attname)
|
||||
for attname in stored_attrs
|
||||
)
|
||||
}
|
||||
|
||||
@property
|
||||
def auth(self):
|
||||
|
@ -1,12 +1,9 @@
|
||||
from __future__ import division
|
||||
import json
|
||||
|
||||
from httpie.compat import is_py26, OrderedDict
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
def load_json_preserve_order(s):
|
||||
if is_py26:
|
||||
return json.loads(s)
|
||||
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
|
||||
docutils
|
||||
wheel
|
||||
pycodestyle
|
||||
|
17
setup.cfg
17
setup.cfg
@ -1,2 +1,19 @@
|
||||
[wheel]
|
||||
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 = [
|
||||
'requests>=2.11.0',
|
||||
'requests>=2.18.4',
|
||||
'Pygments>=2.1.3'
|
||||
]
|
||||
|
||||
@ -58,9 +58,7 @@ if 'bdist_wheel' not in sys.argv:
|
||||
# bdist_wheel
|
||||
extras_require = {
|
||||
# http://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies
|
||||
':python_version == "2.6"'
|
||||
' or python_version == "3.0"'
|
||||
' or python_version == "3.1" ': ['argparse>=1.2.1'],
|
||||
'python_version == "3.0" or python_version == "3.1"': ['argparse>=1.2.1'],
|
||||
':sys_platform == "win32"': ['colorama>=0.2.4'],
|
||||
}
|
||||
|
||||
@ -76,7 +74,7 @@ setup(
|
||||
description=httpie.__doc__.strip(),
|
||||
long_description=long_description(),
|
||||
url='http://httpie.org/',
|
||||
download_url='https://github.com/jkbrzt/httpie',
|
||||
download_url='https://github.com/jakubroztocil/httpie',
|
||||
author=httpie.__author__,
|
||||
author_email='jakub@roztocil.co',
|
||||
license=httpie.__licence__,
|
||||
@ -93,14 +91,14 @@ setup(
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.1',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Environment :: Console',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: System Administrators',
|
||||
|
@ -5,4 +5,4 @@ HTTPie Test Suite
|
||||
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
|
||||
from pytest_httpbin.plugin import httpbin_ca_bundle
|
||||
from pytest_httpbin import certs
|
||||
|
||||
|
||||
# Make httpbin's CA trusted by default
|
||||
pytest.fixture(autouse=True)(httpbin_ca_bundle)
|
||||
@pytest.fixture(scope='function', autouse=True)
|
||||
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')
|
||||
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')
|
||||
return httpbin_secure
|
||||
|
@ -2,7 +2,7 @@
|
||||
import mock
|
||||
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.cli
|
||||
|
||||
@ -55,10 +55,10 @@ def test_credentials_in_url_auth_flag_has_priority(httpbin_both):
|
||||
])
|
||||
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.username == 'username'
|
||||
assert args.auth.password == ''
|
||||
|
@ -2,14 +2,14 @@
|
||||
from fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG
|
||||
from httpie.compat import urlopen
|
||||
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
|
||||
from utils import TestEnvironment, http
|
||||
from utils import MockEnvironment, http
|
||||
|
||||
|
||||
class TestBinaryRequestData:
|
||||
|
||||
def test_binary_stdin(self, httpbin):
|
||||
with open(BIN_FILE_PATH, 'rb') as stdin:
|
||||
env = TestEnvironment(
|
||||
env = MockEnvironment(
|
||||
stdin=stdin,
|
||||
stdin_isatty=False,
|
||||
stdout_isatty=False
|
||||
@ -18,13 +18,13 @@ class TestBinaryRequestData:
|
||||
assert r == BIN_FILE_CONTENT
|
||||
|
||||
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',
|
||||
'@' + BIN_FILE_PATH_ARG, env=env, )
|
||||
assert r == BIN_FILE_CONTENT
|
||||
|
||||
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',
|
||||
'test@' + BIN_FILE_PATH_ARG, env=env)
|
||||
assert bytes(BIN_FILE_CONTENT) in bytes(r)
|
||||
@ -44,12 +44,12 @@ class TestBinaryResponseData:
|
||||
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
||||
|
||||
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,
|
||||
env=env)
|
||||
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
||||
|
||||
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)
|
||||
assert r == self.bindata
|
||||
|
@ -10,7 +10,7 @@ from httpie import input
|
||||
from httpie.input import KeyValue, KeyValueArgType, DataDict
|
||||
from httpie import ExitStatus
|
||||
from httpie.cli import parser
|
||||
from utils import TestEnvironment, http, HTTP_OK
|
||||
from utils import MockEnvironment, http, HTTP_OK
|
||||
from fixtures import (
|
||||
FILE_PATH_ARG, JSON_FILE_PATH_ARG,
|
||||
JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH
|
||||
@ -49,9 +49,9 @@ class TestItemParsing:
|
||||
assert 'bar@baz' in items.files
|
||||
|
||||
@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(
|
||||
self, string, key, sep, value):
|
||||
@ -161,44 +161,44 @@ class TestQuerystring:
|
||||
|
||||
class TestLocalhostShorthand:
|
||||
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'
|
||||
|
||||
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/'
|
||||
|
||||
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'
|
||||
|
||||
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'
|
||||
|
||||
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/'
|
||||
|
||||
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'
|
||||
|
||||
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'
|
||||
|
||||
def test_dont_expand_longer_ipv6_as_shorthand(self):
|
||||
args = parser.parse_args(
|
||||
args=['::ffff:c000:0280'],
|
||||
env=TestEnvironment()
|
||||
env=MockEnvironment()
|
||||
)
|
||||
assert args.url == 'http://::ffff:c000:0280'
|
||||
|
||||
def test_dont_expand_full_ipv6_as_shorthand(self):
|
||||
args = parser.parse_args(
|
||||
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'
|
||||
|
||||
@ -215,7 +215,7 @@ class TestArgumentParser:
|
||||
self.parser.args.items = []
|
||||
self.parser.args.ignore_stdin = False
|
||||
|
||||
self.parser.env = TestEnvironment()
|
||||
self.parser.env = MockEnvironment()
|
||||
|
||||
self.parser._guess_method()
|
||||
|
||||
@ -229,7 +229,7 @@ class TestArgumentParser:
|
||||
self.parser.args.url = 'http://example.com/'
|
||||
self.parser.args.items = []
|
||||
self.parser.args.ignore_stdin = False
|
||||
self.parser.env = TestEnvironment()
|
||||
self.parser.env = MockEnvironment()
|
||||
|
||||
self.parser._guess_method()
|
||||
|
||||
@ -243,7 +243,7 @@ class TestArgumentParser:
|
||||
self.parser.args.url = 'data=field'
|
||||
self.parser.args.items = []
|
||||
self.parser.args.ignore_stdin = False
|
||||
self.parser.env = TestEnvironment()
|
||||
self.parser.env = MockEnvironment()
|
||||
self.parser._guess_method()
|
||||
|
||||
assert self.parser.args.method == 'POST'
|
||||
@ -262,7 +262,7 @@ class TestArgumentParser:
|
||||
self.parser.args.items = []
|
||||
self.parser.args.ignore_stdin = False
|
||||
|
||||
self.parser.env = TestEnvironment()
|
||||
self.parser.env = MockEnvironment()
|
||||
|
||||
self.parser._guess_method()
|
||||
|
||||
@ -285,7 +285,7 @@ class TestArgumentParser:
|
||||
]
|
||||
self.parser.args.ignore_stdin = False
|
||||
|
||||
self.parser.env = TestEnvironment()
|
||||
self.parser.env = MockEnvironment()
|
||||
|
||||
self.parser._guess_method()
|
||||
|
||||
@ -314,7 +314,7 @@ class TestIgnoreStdin:
|
||||
|
||||
def test_ignore_stdin(self, httpbin):
|
||||
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',
|
||||
env=env)
|
||||
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):
|
||||
env = TestEnvironment()
|
||||
env = MockEnvironment()
|
||||
env.config['default_options'] = ['--form']
|
||||
env.config.save()
|
||||
r = http(httpbin.url + '/post', 'foo=bar', env=env)
|
||||
@ -10,7 +12,7 @@ def test_default_options(httpbin):
|
||||
|
||||
|
||||
def test_default_options_overwrite(httpbin):
|
||||
env = TestEnvironment()
|
||||
env = MockEnvironment()
|
||||
env.config['default_options'] = ['--form']
|
||||
env.config.save()
|
||||
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():
|
||||
config = TestEnvironment().config
|
||||
config = MockEnvironment().config
|
||||
|
||||
config['implicit_content_type'] = 'json'
|
||||
config.save()
|
||||
@ -31,3 +33,8 @@ def test_migrate_implicit_content_type():
|
||||
config.load()
|
||||
assert 'implicit_content_type' not in config
|
||||
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 utils import TestEnvironment, http, HTTP_OK
|
||||
from utils import MockEnvironment, http, HTTP_OK
|
||||
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:
|
||||
def test_implicit_GET(self, httpbin):
|
||||
r = http(httpbin.url + '/get')
|
||||
@ -29,7 +44,7 @@ class TestImplicitHTTPMethod:
|
||||
|
||||
def test_implicit_POST_stdin(self, httpbin):
|
||||
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)
|
||||
assert HTTP_OK in r
|
||||
|
||||
@ -43,7 +58,7 @@ class TestAutoContentTypeAndAcceptHeaders:
|
||||
"""
|
||||
|
||||
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')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['headers']['Accept'] == '*/*'
|
||||
@ -74,7 +89,7 @@ class TestAutoContentTypeAndAcceptHeaders:
|
||||
assert HTTP_OK in r
|
||||
assert r.json['headers']['Accept'] == JSON_ACCEPT
|
||||
# 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']
|
||||
|
||||
def test_GET_explicit_JSON_explicit_headers(self, httpbin):
|
||||
@ -97,11 +112,11 @@ class TestAutoContentTypeAndAcceptHeaders:
|
||||
assert '"Content-Type": "application/xml"' in r
|
||||
|
||||
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)
|
||||
assert 'HTTP/' not in r
|
||||
|
||||
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)
|
||||
assert HTTP_OK in r
|
||||
|
@ -10,7 +10,7 @@ from httpie.downloads import (
|
||||
parse_content_range, filename_from_content_disposition, filename_from_url,
|
||||
get_unique_filename, ContentRangeError, Downloader,
|
||||
)
|
||||
from utils import http, TestEnvironment
|
||||
from utils import http, MockEnvironment
|
||||
|
||||
|
||||
class Response(object):
|
||||
@ -123,7 +123,7 @@ class TestDownloads:
|
||||
def test_actual_download(self, httpbin_both, httpbin):
|
||||
robots_txt = '/robots.txt'
|
||||
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)
|
||||
assert 'Downloading' in r.stderr
|
||||
assert '[K' in r.stderr
|
||||
|
@ -1,7 +1,7 @@
|
||||
import mock
|
||||
|
||||
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):
|
||||
@ -21,26 +21,26 @@ def test_keyboard_interrupt_in_program_exit_status(httpbin):
|
||||
def test_ok_response_exits_0(httpbin):
|
||||
r = http('GET', httpbin.url + '/get')
|
||||
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):
|
||||
r = http('GET', httpbin.url + '/status/500')
|
||||
assert '500 INTERNAL SERVER ERRO' in r
|
||||
assert r.exit_status == ExitStatus.OK
|
||||
assert '500 INTERNAL SERVER ERROR' in r
|
||||
assert r.exit_status == ExitStatus.SUCCESS
|
||||
assert not r.stderr
|
||||
|
||||
|
||||
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)
|
||||
assert r.exit_status == ExitStatus.ERROR_TIMEOUT
|
||||
|
||||
|
||||
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(
|
||||
httpbin):
|
||||
env = TestEnvironment(stdout_isatty=False)
|
||||
env = MockEnvironment(stdout_isatty=False)
|
||||
r = http('--check-status', '--headers',
|
||||
'GET', httpbin.url + '/status/301',
|
||||
env=env, error_exit_ok=True)
|
||||
@ -55,7 +55,7 @@ def test_3xx_check_status_redirects_allowed_exits_0(httpbin):
|
||||
error_exit_ok=True)
|
||||
# The redirect will be followed so 200 is expected.
|
||||
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):
|
||||
|
@ -2,28 +2,27 @@
|
||||
import pytest
|
||||
|
||||
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
|
||||
|
||||
import httpie
|
||||
from httpie.compat import is_py26
|
||||
|
||||
|
||||
def test_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
|
||||
|
||||
|
||||
def test_help():
|
||||
r = http('--help', error_exit_ok=True)
|
||||
assert r.exit_status == httpie.ExitStatus.OK
|
||||
assert 'https://github.com/jkbrzt/httpie/issues' in r
|
||||
assert r.exit_status == httpie.ExitStatus.SUCCESS
|
||||
assert 'https://github.com/jakubroztocil/httpie/issues' in r
|
||||
|
||||
|
||||
def test_version():
|
||||
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
|
||||
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):
|
||||
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)
|
||||
assert HTTP_OK 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')
|
||||
|
||||
|
||||
@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):
|
||||
r = http('PATCH', httpbin_both + '/patch',
|
||||
'order:={"map":{"1":"first","2":"second"}}')
|
||||
|
@ -3,7 +3,7 @@ from tempfile import gettempdir
|
||||
|
||||
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.compat import urlopen
|
||||
from httpie.output.formatters.colors import get_lexer
|
||||
@ -15,7 +15,7 @@ def test_output_option(httpbin, stdout_isatty):
|
||||
url = httpbin + '/robots.txt'
|
||||
|
||||
r = http('--output', output_filename, url,
|
||||
env=TestEnvironment(stdout_isatty=stdout_isatty))
|
||||
env=MockEnvironment(stdout_isatty=stdout_isatty))
|
||||
assert r == ''
|
||||
|
||||
expected_body = urlopen(url).read().decode()
|
||||
@ -33,7 +33,7 @@ class TestVerboseFlag:
|
||||
assert r.count('__test__') == 2
|
||||
|
||||
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',
|
||||
'A=B', 'C=D')
|
||||
assert HTTP_OK in r
|
||||
@ -86,7 +86,7 @@ class TestPrettyOptions:
|
||||
"""Test the --pretty flag handling."""
|
||||
|
||||
def test_pretty_enabled_by_default(self, httpbin):
|
||||
env = TestEnvironment(colors=256)
|
||||
env = MockEnvironment(colors=256)
|
||||
r = http('GET', httpbin.url + '/get', env=env)
|
||||
assert COLOR in r
|
||||
|
||||
@ -95,7 +95,7 @@ class TestPrettyOptions:
|
||||
assert COLOR not in r
|
||||
|
||||
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, )
|
||||
assert COLOR in r
|
||||
|
||||
@ -108,13 +108,13 @@ class TestPrettyOptions:
|
||||
match any lexer.
|
||||
|
||||
"""
|
||||
env = TestEnvironment(colors=256)
|
||||
env = MockEnvironment(colors=256)
|
||||
r = http('--print=B', '--pretty=all', httpbin.url + '/post',
|
||||
'Content-Type:text/foo+json', 'a=b', env=env)
|
||||
assert COLOR in r
|
||||
|
||||
def test_colors_option(self, httpbin):
|
||||
env = TestEnvironment(colors=256)
|
||||
env = MockEnvironment(colors=256)
|
||||
r = http('--print=B', '--pretty=colors',
|
||||
'GET', httpbin.url + '/get', 'a=b',
|
||||
env=env)
|
||||
@ -123,7 +123,7 @@ class TestPrettyOptions:
|
||||
assert COLOR in r
|
||||
|
||||
def test_format_option(self, httpbin):
|
||||
env = TestEnvironment(colors=256)
|
||||
env = MockEnvironment(colors=256)
|
||||
r = http('--print=B', '--pretty=format',
|
||||
'GET', httpbin.url + '/get', 'a=b',
|
||||
env=env)
|
||||
@ -161,7 +161,7 @@ class TestLineEndings:
|
||||
|
||||
def test_CRLF_formatted_response(self, httpbin):
|
||||
r = http('--pretty=format', 'GET', httpbin.url + '/get')
|
||||
assert r.exit_status == ExitStatus.OK
|
||||
assert r.exit_status == ExitStatus.SUCCESS
|
||||
self._validate_crlf(r)
|
||||
|
||||
def test_CRLF_ugly_request(self, httpbin):
|
||||
|
@ -7,7 +7,7 @@ from httpie.compat import is_windows
|
||||
|
||||
def test_Host_header_overwrite(httpbin):
|
||||
"""
|
||||
https://github.com/jkbrzt/httpie/issues/235
|
||||
https://github.com/jakubroztocil/httpie/issues/235
|
||||
|
||||
"""
|
||||
host = 'httpbin.org'
|
||||
@ -21,7 +21,7 @@ def test_Host_header_overwrite(httpbin):
|
||||
@pytest.mark.skipif(is_windows, reason='Unix-only')
|
||||
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')
|
||||
|
@ -7,7 +7,7 @@ from tempfile import gettempdir
|
||||
import pytest
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ class SessionTestBase(object):
|
||||
for session files being reused.
|
||||
|
||||
"""
|
||||
return TestEnvironment(config_dir=self.config_dir)
|
||||
return MockEnvironment(config_dir=self.config_dir)
|
||||
|
||||
|
||||
class TestSessionFlow(SessionTestBase):
|
||||
@ -81,8 +81,8 @@ class TestSessionFlow(SessionTestBase):
|
||||
assert HTTP_OK in r4
|
||||
assert r4.json['headers']['Hello'] == 'World2'
|
||||
assert r4.json['headers']['Cookie'] == 'hello=world2'
|
||||
assert (r2.json['headers']['Authorization'] !=
|
||||
r4.json['headers']['Authorization'])
|
||||
assert (r2.json['headers']['Authorization']
|
||||
!= r4.json['headers']['Authorization'])
|
||||
|
||||
def test_session_read_only(self, httpbin):
|
||||
self.start_session(httpbin)
|
||||
@ -143,7 +143,7 @@ class TestSession(SessionTestBase):
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info >= (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):
|
||||
self.start_session(httpbin)
|
||||
|
||||
@ -157,14 +157,14 @@ class TestSession(SessionTestBase):
|
||||
assert HTTP_OK in r2
|
||||
|
||||
# FIXME: Authorization *sometimes* is not present on Python3
|
||||
assert (r2.json['headers']['Authorization'] ==
|
||||
HTTPBasicAuth.make_header(u'test', UNICODE))
|
||||
assert (r2.json['headers']['Authorization']
|
||||
== HTTPBasicAuth.make_header(u'test', UNICODE))
|
||||
# httpbin doesn't interpret utf8 headers
|
||||
assert UNICODE in r2
|
||||
|
||||
def test_session_default_header_value_overwritten(self, httpbin):
|
||||
self.start_session(httpbin)
|
||||
# https://github.com/jkbrzt/httpie/issues/180
|
||||
# https://github.com/jakubroztocil/httpie/issues/180
|
||||
r1 = http('--session=test',
|
||||
httpbin.url + '/headers', 'User-Agent:custom',
|
||||
env=self.env())
|
||||
@ -176,7 +176,7 @@ class TestSession(SessionTestBase):
|
||||
assert r2.json['headers']['User-Agent'] == 'custom'
|
||||
|
||||
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)
|
||||
cwd = os.getcwd()
|
||||
os.chdir(gettempdir())
|
||||
|
@ -73,6 +73,11 @@ class TestServerCert:
|
||||
r = http(httpbin_secure.url + '/get', '--verify=no')
|
||||
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(
|
||||
self, httpbin_secure_untrusted):
|
||||
r = http(httpbin_secure_untrusted + '/get', '--verify', CA_BUNDLE)
|
||||
@ -85,7 +90,8 @@ class TestServerCert:
|
||||
http(httpbin_secure_untrusted.url + '/get')
|
||||
|
||||
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__')
|
||||
|
||||
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.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
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH
|
||||
def test_pretty_redirected_stream(httpbin):
|
||||
"""Test that --stream works with prettified redirected output."""
|
||||
with open(BIN_FILE_PATH, 'rb') as f:
|
||||
env = TestEnvironment(colors=256, stdin=f,
|
||||
env = MockEnvironment(colors=256, stdin=f,
|
||||
stdin_isatty=False,
|
||||
stdout_isatty=False)
|
||||
r = http('--verbose', '--pretty=all', '--stream', 'GET',
|
||||
@ -26,7 +26,7 @@ def test_encoded_stream(httpbin):
|
||||
"""Test that --stream works with non-prettified
|
||||
redirected terminal output."""
|
||||
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',
|
||||
httpbin.url + '/get', env=env)
|
||||
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
||||
@ -36,7 +36,7 @@ def test_redirected_stream(httpbin):
|
||||
"""Test that --stream works with non-prettified
|
||||
redirected terminal output."""
|
||||
with open(BIN_FILE_PATH, 'rb') as f:
|
||||
env = TestEnvironment(stdout_isatty=False,
|
||||
env = MockEnvironment(stdout_isatty=False,
|
||||
stdin_isatty=False,
|
||||
stdin=f)
|
||||
r = http('--pretty=none', '--stream', '--verbose', 'GET',
|
||||
|
@ -3,7 +3,7 @@ import os
|
||||
import pytest
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -62,14 +62,14 @@ class TestRequestBodyFromFilePath:
|
||||
|
||||
def test_request_body_from_file_by_path_no_field_name_allowed(
|
||||
self, httpbin):
|
||||
env = TestEnvironment(stdin_isatty=True)
|
||||
env = MockEnvironment(stdin_isatty=True)
|
||||
r = http('POST', httpbin.url + '/post', 'field-name@' + FILE_PATH_ARG,
|
||||
env=env, error_exit_ok=True)
|
||||
assert 'perhaps you meant --form?' in r.stderr
|
||||
|
||||
def test_request_body_from_file_by_path_no_data_items_allowed(
|
||||
self, httpbin):
|
||||
env = TestEnvironment(stdin_isatty=False)
|
||||
env = MockEnvironment(stdin_isatty=False)
|
||||
r = http('POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, 'foo=bar',
|
||||
env=env, error_exit_ok=True)
|
||||
assert 'cannot be mixed' in r.stderr
|
||||
|
@ -4,7 +4,7 @@ import tempfile
|
||||
import pytest
|
||||
from httpie.context import Environment
|
||||
|
||||
from utils import TestEnvironment, http
|
||||
from utils import MockEnvironment, http
|
||||
from httpie.compat import is_windows
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ class TestWindowsOnly:
|
||||
|
||||
class TestFakeWindows:
|
||||
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(
|
||||
tempfile.gettempdir(),
|
||||
self.test_output_file_pretty_not_allowed_on_windows.__name__
|
||||
|
@ -33,7 +33,7 @@ def add_auth(url, auth):
|
||||
return proto + '://' + auth + '@' + rest
|
||||
|
||||
|
||||
class TestEnvironment(Environment):
|
||||
class MockEnvironment(Environment):
|
||||
"""Environment subclass with reasonable defaults for testing."""
|
||||
colors = 0
|
||||
stdin_isatty = True,
|
||||
@ -51,7 +51,7 @@ class TestEnvironment(Environment):
|
||||
mode='w+t',
|
||||
prefix='httpie_stderr'
|
||||
)
|
||||
super(TestEnvironment, self).__init__(**kwargs)
|
||||
super(MockEnvironment, self).__init__(**kwargs)
|
||||
self._delete_config_dir = False
|
||||
|
||||
@property
|
||||
@ -59,7 +59,7 @@ class TestEnvironment(Environment):
|
||||
if not self.config_dir.startswith(tempfile.gettempdir()):
|
||||
self.config_dir = mk_config_dir()
|
||||
self._delete_config_dir = True
|
||||
return super(TestEnvironment, self).config
|
||||
return super(MockEnvironment, self).config
|
||||
|
||||
def cleanup(self):
|
||||
if self._delete_config_dir:
|
||||
@ -119,8 +119,8 @@ class StrCLIResponse(str, BaseCLIResponse):
|
||||
elif self.strip().startswith('{'):
|
||||
# Looks like JSON body.
|
||||
self._json = json.loads(self)
|
||||
elif (self.count('Content-Type:') == 1 and
|
||||
'application/json' in self):
|
||||
elif (self.count('Content-Type:') == 1
|
||||
and 'application/json' in self):
|
||||
# Looks like a whole JSON HTTP message,
|
||||
# try to extract its body.
|
||||
try:
|
||||
@ -183,7 +183,7 @@ def http(*args, **kwargs):
|
||||
error_exit_ok = kwargs.pop('error_exit_ok', False)
|
||||
env = kwargs.get('env')
|
||||
if not env:
|
||||
env = kwargs['env'] = TestEnvironment()
|
||||
env = kwargs['env'] = MockEnvironment()
|
||||
|
||||
stdout = env.stdout
|
||||
stderr = env.stderr
|
||||
@ -219,7 +219,7 @@ def http(*args, **kwargs):
|
||||
sys.stderr.write(stderr.read())
|
||||
raise
|
||||
else:
|
||||
if not error_exit_ok and exit_status != ExitStatus.OK:
|
||||
if not error_exit_ok and exit_status != ExitStatus.SUCCESS:
|
||||
dump_stderr()
|
||||
raise ExitStatusError(
|
||||
'httpie.core.main() unexpectedly returned'
|
||||
@ -243,7 +243,7 @@ def http(*args, **kwargs):
|
||||
r.stderr = stderr.read()
|
||||
r.exit_status = exit_status
|
||||
|
||||
if r.exit_status != ExitStatus.OK:
|
||||
if r.exit_status != ExitStatus.SUCCESS:
|
||||
sys.stderr.write(r.stderr)
|
||||
|
||||
return r
|
||||
|
12
tox.ini
12
tox.ini
@ -3,7 +3,8 @@
|
||||
|
||||
|
||||
[tox]
|
||||
envlist = py26, py27, py35, pypy, codestyle
|
||||
# pypy3 currently fails because of a Flask issue
|
||||
envlist = py27, py37, pypy
|
||||
|
||||
|
||||
[testenv]
|
||||
@ -21,10 +22,5 @@ commands =
|
||||
--doctest-modules \
|
||||
{posargs:./httpie ./tests}
|
||||
|
||||
[testenv:codestyle]
|
||||
deps = pycodestyle
|
||||
commands =
|
||||
pycodestyle \
|
||||
--ignore=E241,E501
|
||||
# 241 - multiple spaces after ‘,’
|
||||
# 501 - line too long
|
||||
[testenv:py27-osx-builtin]
|
||||
basepython = /usr/bin/python2.7
|
||||
|
Reference in New Issue
Block a user