mirror of
https://github.com/httpie/cli.git
synced 2025-06-24 19:41:23 +02:00
Build fixes and clean-up
* reflect Python 3.7 release * fix `pycodestyle` errors * update `pycodestyle` config * move `pytest` and `pycodestyle` config to `setup.cfg` * add `make pycodestyle` * add `make coveralls` * etc.
This commit is contained in:
parent
a50660cc70
commit
7917f1b40c
@ -1 +0,0 @@
|
|||||||
; needs to exist otherwise `$ coveralls` fails
|
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -2,12 +2,12 @@
|
|||||||
.idea/
|
.idea/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
dist/
|
dist/
|
||||||
httpie.egg-info/
|
|
||||||
build/
|
build/
|
||||||
*.egg-info
|
*.egg-info
|
||||||
.cache/
|
.cache/
|
||||||
.tox
|
.tox/
|
||||||
.coverage
|
.coverage
|
||||||
*.pyc
|
*.pyc
|
||||||
*.egg
|
*.egg
|
||||||
htmlcov
|
htmlcov
|
||||||
|
.pytest_cache/
|
||||||
|
88
.travis.yml
88
.travis.yml
@ -1,95 +1,77 @@
|
|||||||
# https://travis-ci.org/jakubroztocil/httpie
|
# <https://travis-ci.org/jakubroztocil/httpie>
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
language: python
|
language: python
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- NEWEST_PYTHON=3.6
|
- NEWEST_PYTHON=3.7
|
||||||
|
|
||||||
python:
|
python:
|
||||||
- 2.7
|
- 2.7
|
||||||
- pypy
|
|
||||||
- 3.4
|
- 3.4
|
||||||
- 3.5
|
- 3.5
|
||||||
- 3.6
|
- 3.6
|
||||||
# Currently fails because of a Flask issue
|
- 3.7
|
||||||
# - pypy3
|
- pypy
|
||||||
|
# pypy3 currently fails because of a Flask issue
|
||||||
|
# - pypy3
|
||||||
cache: pip
|
cache: pip
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
|
||||||
include:
|
include:
|
||||||
|
# Add manually defined OS X builds
|
||||||
# Manually defined OS X builds
|
# <https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages)>
|
||||||
# https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages)
|
|
||||||
|
|
||||||
# Stock OSX Python
|
|
||||||
- os: osx
|
- os: osx
|
||||||
language: generic
|
language: generic
|
||||||
env:
|
env:
|
||||||
|
# Stock OSX Python
|
||||||
- TOXENV=py27
|
- TOXENV=py27
|
||||||
|
- BREW_PYTHON_PACKAGE=
|
||||||
# Latest Python 2.x from Homebrew
|
|
||||||
- os: osx
|
- os: osx
|
||||||
language: generic
|
language: generic
|
||||||
env:
|
env:
|
||||||
|
# Latest Python 2.7 from Homebrew
|
||||||
- TOXENV=py27
|
- TOXENV=py27
|
||||||
- BREW_INSTALL=python
|
- BREW_PYTHON_PACKAGE=python@2
|
||||||
|
|
||||||
# Latest Python 3.x from Homebrew
|
|
||||||
- os: osx
|
- os: osx
|
||||||
language: generic
|
language: generic
|
||||||
env:
|
env:
|
||||||
- TOXENV=py36
|
# Latest Python 3.x from Homebrew
|
||||||
- BREW_INSTALL=python3
|
- TOXENV=py37 # <= needs to be kept up-to-date to reflect latest minor version
|
||||||
|
- BREW_PYTHON_PACKAGE=python@3
|
||||||
# Python Codestyle
|
# Add a codestyle-only build
|
||||||
- os: linux
|
- os: linux
|
||||||
python: 3.6
|
python: 3.6
|
||||||
env: CODESTYLE=true
|
env: CODESTYLE_ONLY=true
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- |
|
- |
|
||||||
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
|
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
|
||||||
if [[ -n "$BREW_INSTALL" ]]; then
|
sudo pip install tox
|
||||||
brew update
|
if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then
|
||||||
brew install "$BREW_INSTALL"
|
brew install "$BREW_PYTHON_PACKAGE"
|
||||||
fi
|
fi
|
||||||
sudo pip install tox
|
|
||||||
fi
|
fi
|
||||||
if [[ $CODESTYLE ]]; then
|
|
||||||
pip install pycodestyle
|
|
||||||
fi
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||||
if [[ $CODESTYLE ]]; then
|
if [[ $CODESTYLE_ONLY ]]; then
|
||||||
# 241 - multiple spaces after ‘,’
|
make pycodestyle
|
||||||
# 501 - line too long
|
else
|
||||||
pycodestyle --ignore=E241,E501
|
make test
|
||||||
else
|
fi
|
||||||
make
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
PATH="/usr/local/bin:$PATH" tox -e "$TOXENV"
|
PATH="/usr/local/bin:$PATH" tox -e "$TOXENV"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- |
|
- |
|
||||||
if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux' ]]; then
|
if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||||
pip install python-coveralls && coveralls
|
make coveralls
|
||||||
fi
|
fi
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
|
|
||||||
webhooks:
|
webhooks:
|
||||||
|
# options: [always|never|change] default: always
|
||||||
|
on_success: always
|
||||||
|
on_failure: always
|
||||||
|
on_start: always
|
||||||
urls:
|
urls:
|
||||||
# https://gitter.im/jkbrzt/httpie
|
# https://gitter.im/jkbrzt/httpie
|
||||||
- https://webhooks.gitter.im/e/c42fcd359a110d02830b
|
- https://webhooks.gitter.im/e/c42fcd359a110d02830b
|
||||||
on_success: always # options: [always|never|change] default: always
|
|
||||||
on_failure: always # options: [always|never|change] default: always
|
|
||||||
on_start: always # options: [always|never|change] default: always
|
|
||||||
|
@ -53,7 +53,8 @@ Go to https://github.com/jakubroztocil/httpie and fork the project repository.
|
|||||||
Making Changes
|
Making Changes
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8).
|
Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8)
|
||||||
|
and that ``make pycodestyle`` passes.
|
||||||
|
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
@ -80,6 +81,9 @@ Running all tests:
|
|||||||
# Run all tests for code as well as packaging, etc.
|
# Run all tests for code as well as packaging, etc.
|
||||||
make test-all
|
make test-all
|
||||||
|
|
||||||
|
# Test PEP8 compliance
|
||||||
|
make pycodestyle
|
||||||
|
|
||||||
|
|
||||||
Running specific tests:
|
Running specific tests:
|
||||||
***********************
|
***********************
|
||||||
@ -92,11 +96,11 @@ Running specific tests:
|
|||||||
py.test tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok
|
py.test tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok
|
||||||
|
|
||||||
# Run specific tests on the on all Pythons via Tox
|
# Run specific tests on the on all Pythons via Tox
|
||||||
|
# (change to `tox -e py37' to limit Python version)
|
||||||
tox -- tests/test_uploads.py --verbose
|
tox -- tests/test_uploads.py --verbose
|
||||||
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload --verbose
|
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload --verbose
|
||||||
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok --verbose
|
tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok --verbose
|
||||||
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
See `Makefile`_ for additional development utilities.
|
See `Makefile`_ for additional development utilities.
|
||||||
|
57
Makefile
57
Makefile
@ -1,6 +1,6 @@
|
|||||||
#
|
###############################################################################
|
||||||
# See ./CONTRIBUTING.rst
|
# See ./CONTRIBUTING.rst
|
||||||
#
|
###############################################################################
|
||||||
|
|
||||||
VERSION=$(shell grep __version__ httpie/__init__.py)
|
VERSION=$(shell grep __version__ httpie/__init__.py)
|
||||||
REQUIREMENTS="requirements-dev.txt"
|
REQUIREMENTS="requirements-dev.txt"
|
||||||
@ -20,6 +20,17 @@ init: uninstall-httpie
|
|||||||
|
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo $(TAG)Cleaning up$(END)
|
||||||
|
rm -rf .tox *.egg dist build .coverage .cache .pytest_cache httpie.egg-info
|
||||||
|
find . -name '__pycache__' -delete -print -o -name '*.pyc' -delete -print
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Testing
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
test: init
|
test: init
|
||||||
@echo $(TAG)Running tests on the current Python interpreter with coverage $(END)
|
@echo $(TAG)Running tests on the current Python interpreter with coverage $(END)
|
||||||
@ -27,9 +38,8 @@ test: init
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
test-tox: init
|
# test-all is meant to test everything — even this Makefile
|
||||||
@echo $(TAG)Running tests on all Pythons via Tox$(END)
|
test-all: uninstall-all clean init test test-tox test-dist pycodestyle
|
||||||
tox
|
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +47,12 @@ test-dist: test-sdist test-bdist-wheel
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
test-tox: init
|
||||||
|
@echo $(TAG)Running tests on all Pythons via Tox$(END)
|
||||||
|
tox
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
test-sdist: clean uninstall-httpie
|
test-sdist: clean uninstall-httpie
|
||||||
@echo $(TAG)Testing sdist build an installation$(END)
|
@echo $(TAG)Testing sdist build an installation$(END)
|
||||||
python setup.py sdist
|
python setup.py sdist
|
||||||
@ -53,12 +69,26 @@ test-bdist-wheel: clean uninstall-httpie
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
# This tests everything, even this Makefile.
|
pycodestyle:
|
||||||
test-all: uninstall-all clean init test test-tox test-dist
|
which pycodestyle || pip install pycodestyle
|
||||||
|
pycodestyle
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
coveralls:
|
||||||
|
which coveralls || pip install python-coveralls
|
||||||
|
coveralls
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Publishing to PyPi
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
publish: test-all publish-no-test
|
publish: test-all publish-no-test
|
||||||
|
|
||||||
|
|
||||||
publish-no-test:
|
publish-no-test:
|
||||||
@echo $(TAG)Testing wheel build an installation$(END)
|
@echo $(TAG)Testing wheel build an installation$(END)
|
||||||
@echo "$(VERSION)"
|
@echo "$(VERSION)"
|
||||||
@ -69,12 +99,10 @@ publish-no-test:
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@echo $(TAG)Cleaning up$(END)
|
|
||||||
rm -rf .tox *.egg dist build .coverage
|
|
||||||
find . -name '__pycache__' -delete -print -o -name '*.pyc' -delete -print
|
|
||||||
@echo
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Uninstalling
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
uninstall-httpie:
|
uninstall-httpie:
|
||||||
@echo $(TAG)Uninstalling httpie$(END)
|
@echo $(TAG)Uninstalling httpie$(END)
|
||||||
@ -96,5 +124,10 @@ uninstall-all: uninstall-httpie
|
|||||||
- pip uninstall --yes -r $(REQUIREMENTS)
|
- pip uninstall --yes -r $(REQUIREMENTS)
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Utils
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
homebrew-formula-vars:
|
homebrew-formula-vars:
|
||||||
extras/get-homebrew-formula-vars.py
|
extras/get-homebrew-formula-vars.py
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""
|
"""
|
||||||
Generate URLs and file hashes to be included in the Homebrew formula
|
Generate URLs and file hashes to be included in the Homebrew formula
|
||||||
after a new release of HTTPie is published on PyPi.
|
after a new release of HTTPie has been published on PyPi.
|
||||||
|
|
||||||
https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb
|
https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ PACKAGES = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_info(package_name):
|
def get_package_meta(package_name):
|
||||||
api_url = 'https://pypi.python.org/pypi/{}/json'.format(package_name)
|
api_url = 'https://pypi.python.org/pypi/{}/json'.format(package_name)
|
||||||
resp = requests.get(api_url).json()
|
resp = requests.get(api_url).json()
|
||||||
hasher = hashlib.sha256()
|
hasher = hashlib.sha256()
|
||||||
@ -35,21 +35,23 @@ def get_info(package_name):
|
|||||||
'{}: download not found: {}'.format(package_name, resp))
|
'{}: download not found: {}'.format(package_name, resp))
|
||||||
|
|
||||||
|
|
||||||
packages = {
|
def main():
|
||||||
package_name: get_info(package_name) for package_name in PACKAGES
|
package_meta_map = {
|
||||||
}
|
package_name: get_package_meta(package_name)
|
||||||
|
for package_name in PACKAGES
|
||||||
|
}
|
||||||
|
httpie_meta = package_meta_map.pop('httpie')
|
||||||
|
print()
|
||||||
|
print(' url "{url}"'.format(url=httpie_meta['url']))
|
||||||
|
print(' sha256 "{sha256}"'.format(sha256=httpie_meta['sha256']))
|
||||||
|
print()
|
||||||
|
for dep_meta in package_meta_map.values():
|
||||||
|
print(' resource "{name}" do'.format(name=dep_meta['name']))
|
||||||
|
print(' url "{url}"'.format(url=dep_meta['url']))
|
||||||
|
print(' sha256 "{sha256}"'.format(sha256=dep_meta['sha256']))
|
||||||
|
print(' end')
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
httpie_info = packages.pop('httpie')
|
if __name__ == '__main__':
|
||||||
print("""
|
main()
|
||||||
url "{url}"
|
|
||||||
sha256 "{sha256}"
|
|
||||||
""".format(**httpie_info))
|
|
||||||
|
|
||||||
|
|
||||||
for package_info in packages.values():
|
|
||||||
print("""
|
|
||||||
resource "{name}" do
|
|
||||||
url "{url}"
|
|
||||||
sha256 "{sha256}"
|
|
||||||
end""".format(**package_info))
|
|
||||||
|
@ -164,8 +164,8 @@ def program(args, env, log_error):
|
|||||||
if downloader and not downloader.finished:
|
if downloader and not downloader.finished:
|
||||||
downloader.failed()
|
downloader.failed()
|
||||||
|
|
||||||
if (not isinstance(args, list) and args.output_file and
|
if (not isinstance(args, list) and args.output_file
|
||||||
args.output_file_specified):
|
and args.output_file_specified):
|
||||||
args.output_file.close()
|
args.output_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ def parse_content_range(content_range, resumed_from):
|
|||||||
raise ContentRangeError('Missing Content-Range')
|
raise ContentRangeError('Missing Content-Range')
|
||||||
|
|
||||||
pattern = (
|
pattern = (
|
||||||
'^bytes (?P<first_byte_pos>\d+)-(?P<last_byte_pos>\d+)'
|
r'^bytes (?P<first_byte_pos>\d+)-(?P<last_byte_pos>\d+)'
|
||||||
'/(\*|(?P<instance_length>\d+))$'
|
r'/(\*|(?P<instance_length>\d+))$'
|
||||||
)
|
)
|
||||||
match = re.match(pattern, content_range)
|
match = re.match(pattern, content_range)
|
||||||
|
|
||||||
@ -78,15 +78,15 @@ def parse_content_range(content_range, resumed_from):
|
|||||||
# last-byte-pos value, is invalid. The recipient of an invalid
|
# last-byte-pos value, is invalid. The recipient of an invalid
|
||||||
# byte-content-range- spec MUST ignore it and any content
|
# byte-content-range- spec MUST ignore it and any content
|
||||||
# transferred along with it."
|
# transferred along with it."
|
||||||
if (first_byte_pos >= last_byte_pos or
|
if (first_byte_pos >= last_byte_pos
|
||||||
(instance_length is not None and
|
or (instance_length is not None
|
||||||
instance_length <= last_byte_pos)):
|
and instance_length <= last_byte_pos)):
|
||||||
raise ContentRangeError(
|
raise ContentRangeError(
|
||||||
'Invalid Content-Range returned: %r' % content_range)
|
'Invalid Content-Range returned: %r' % content_range)
|
||||||
|
|
||||||
if (first_byte_pos != resumed_from or
|
if (first_byte_pos != resumed_from
|
||||||
(instance_length is not None and
|
or (instance_length is not None
|
||||||
last_byte_pos + 1 != instance_length)):
|
and last_byte_pos + 1 != instance_length)):
|
||||||
# Not what we asked for.
|
# Not what we asked for.
|
||||||
raise ContentRangeError(
|
raise ContentRangeError(
|
||||||
'Unexpected Content-Range returned (%r)'
|
'Unexpected Content-Range returned (%r)'
|
||||||
@ -308,9 +308,9 @@ class Downloader(object):
|
|||||||
@property
|
@property
|
||||||
def interrupted(self):
|
def interrupted(self):
|
||||||
return (
|
return (
|
||||||
self.finished and
|
self.finished
|
||||||
self.status.total_size and
|
and self.status.total_size
|
||||||
self.status.total_size != self.status.downloaded
|
and self.status.total_size != self.status.downloaded
|
||||||
)
|
)
|
||||||
|
|
||||||
def chunk_downloaded(self, chunk):
|
def chunk_downloaded(self, chunk):
|
||||||
@ -399,8 +399,8 @@ class ProgressReporterThread(threading.Thread):
|
|||||||
if now - self._prev_time >= self._update_interval:
|
if now - self._prev_time >= self._update_interval:
|
||||||
downloaded = self.status.downloaded
|
downloaded = self.status.downloaded
|
||||||
try:
|
try:
|
||||||
speed = ((downloaded - self._prev_bytes) /
|
speed = ((downloaded - self._prev_bytes)
|
||||||
(now - self._prev_time))
|
/ (now - self._prev_time))
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
speed = 0
|
speed = 0
|
||||||
|
|
||||||
@ -434,11 +434,11 @@ class ProgressReporterThread(threading.Thread):
|
|||||||
self._prev_bytes = downloaded
|
self._prev_bytes = downloaded
|
||||||
|
|
||||||
self.output.write(
|
self.output.write(
|
||||||
CLEAR_LINE +
|
CLEAR_LINE
|
||||||
' ' +
|
+ ' '
|
||||||
SPINNER[self._spinner_pos] +
|
+ SPINNER[self._spinner_pos]
|
||||||
' ' +
|
+ ' '
|
||||||
self._status_line
|
+ self._status_line
|
||||||
)
|
)
|
||||||
self.output.flush()
|
self.output.flush()
|
||||||
|
|
||||||
@ -463,8 +463,8 @@ class ProgressReporterThread(threading.Thread):
|
|||||||
|
|
||||||
self.output.write(SUMMARY.format(
|
self.output.write(SUMMARY.format(
|
||||||
downloaded=humanize_bytes(actually_downloaded),
|
downloaded=humanize_bytes(actually_downloaded),
|
||||||
total=(self.status.total_size and
|
total=(self.status.total_size
|
||||||
humanize_bytes(self.status.total_size)),
|
and humanize_bytes(self.status.total_size)),
|
||||||
speed=humanize_bytes(speed),
|
speed=humanize_bytes(speed),
|
||||||
time=time_taken,
|
time=time_taken,
|
||||||
))
|
))
|
||||||
|
@ -254,8 +254,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
|||||||
else:
|
else:
|
||||||
credentials = parse_auth(self.args.auth)
|
credentials = parse_auth(self.args.auth)
|
||||||
|
|
||||||
if (not credentials.has_password() and
|
if (not credentials.has_password()
|
||||||
plugin.prompt_password):
|
and plugin.prompt_password):
|
||||||
if self.args.ignore_stdin:
|
if self.args.ignore_stdin:
|
||||||
# Non-tty stdin read by now
|
# Non-tty stdin read by now
|
||||||
self.error(
|
self.error(
|
||||||
@ -338,10 +338,11 @@ class HTTPieArgumentParser(ArgumentParser):
|
|||||||
self.args.url = self.args.method
|
self.args.url = self.args.method
|
||||||
# Infer the method
|
# Infer the method
|
||||||
has_data = (
|
has_data = (
|
||||||
(not self.args.ignore_stdin and
|
(not self.args.ignore_stdin and not self.env.stdin_isatty)
|
||||||
not self.env.stdin_isatty) or
|
or any(
|
||||||
any(item.sep in SEP_GROUP_DATA_ITEMS
|
item.sep in SEP_GROUP_DATA_ITEMS
|
||||||
for item in self.args.items)
|
for item in self.args.items
|
||||||
|
)
|
||||||
)
|
)
|
||||||
self.args.method = HTTP_POST if has_data else HTTP_GET
|
self.args.method = HTTP_POST if has_data else HTTP_GET
|
||||||
|
|
||||||
@ -426,8 +427,8 @@ class HTTPieArgumentParser(ArgumentParser):
|
|||||||
if self.args.prettify == PRETTY_STDOUT_TTY_ONLY:
|
if self.args.prettify == PRETTY_STDOUT_TTY_ONLY:
|
||||||
self.args.prettify = PRETTY_MAP[
|
self.args.prettify = PRETTY_MAP[
|
||||||
'all' if self.env.stdout_isatty else 'none']
|
'all' if self.env.stdout_isatty else 'none']
|
||||||
elif (self.args.prettify and self.env.is_windows and
|
elif (self.args.prettify and self.env.is_windows
|
||||||
self.args.output_file):
|
and self.args.output_file):
|
||||||
self.error('Only terminal output can be colorized on Windows.')
|
self.error('Only terminal output can be colorized on Windows.')
|
||||||
else:
|
else:
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
@ -469,8 +470,8 @@ class SessionNameValidator(object):
|
|||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
# Session name can be a path or just a name.
|
# Session name can be a path or just a name.
|
||||||
if (os.path.sep not in value and
|
if (os.path.sep not in value
|
||||||
not VALID_SESSION_NAME_PATTERN.search(value)):
|
and not VALID_SESSION_NAME_PATTERN.search(value)):
|
||||||
raise ArgumentError(None, self.error_message)
|
raise ArgumentError(None, self.error_message)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -505,7 +506,7 @@ class KeyValueArgType(object):
|
|||||||
"""Represents an escaped character."""
|
"""Represents an escaped character."""
|
||||||
|
|
||||||
def tokenize(string):
|
def tokenize(string):
|
||||||
"""Tokenize `string`. There are only two token types - strings
|
r"""Tokenize `string`. There are only two token types - strings
|
||||||
and escaped characters:
|
and escaped characters:
|
||||||
|
|
||||||
tokenize(r'foo\=bar\\baz')
|
tokenize(r'foo\=bar\\baz')
|
||||||
|
@ -15,8 +15,8 @@ class JSONFormatter(FormatterPlugin):
|
|||||||
'javascript',
|
'javascript',
|
||||||
'text',
|
'text',
|
||||||
]
|
]
|
||||||
if (self.kwargs['explicit_json'] or
|
if (self.kwargs['explicit_json']
|
||||||
any(token in mime for token in maybe_json)):
|
or any(token in mime for token in maybe_json)):
|
||||||
try:
|
try:
|
||||||
obj = json.loads(body)
|
obj = json.loads(body)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -30,8 +30,8 @@ def get_response(requests_session, session_name,
|
|||||||
if os.path.sep in session_name:
|
if os.path.sep in session_name:
|
||||||
path = os.path.expanduser(session_name)
|
path = os.path.expanduser(session_name)
|
||||||
else:
|
else:
|
||||||
hostname = (args.headers.get('Host', None) or
|
hostname = (args.headers.get('Host', None)
|
||||||
urlsplit(args.url).netloc.split('@')[-1])
|
or urlsplit(args.url).netloc.split('@')[-1])
|
||||||
if not hostname:
|
if not hostname:
|
||||||
# HACK/FIXME: httpie-unixsocket's URLs have no hostname.
|
# HACK/FIXME: httpie-unixsocket's URLs have no hostname.
|
||||||
hostname = 'localhost'
|
hostname = 'localhost'
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
[pytest]
|
|
||||||
norecursedirs = tests/fixtures
|
|
@ -5,3 +5,4 @@ pytest-cov
|
|||||||
pytest-httpbin>=0.0.6
|
pytest-httpbin>=0.0.6
|
||||||
docutils
|
docutils
|
||||||
wheel
|
wheel
|
||||||
|
pycodestyle
|
||||||
|
17
setup.cfg
17
setup.cfg
@ -1,2 +1,19 @@
|
|||||||
[wheel]
|
[wheel]
|
||||||
universal = 1
|
universal = 1
|
||||||
|
|
||||||
|
|
||||||
|
[tool:pytest]
|
||||||
|
# <https://docs.pytest.org/en/latest/customize.html>
|
||||||
|
norecursedirs = tests/fixtures
|
||||||
|
|
||||||
|
|
||||||
|
[pycodestyle]
|
||||||
|
# <http://pycodestyle.pycqa.org/en/latest/intro.html#configuration>
|
||||||
|
|
||||||
|
exclude = .git,.idea,__pycache__,build,dist,.tox,.pytest_cache,*.egg-info
|
||||||
|
|
||||||
|
# <http://pycodestyle.pycqa.org/en/latest/intro.html#error-codes>
|
||||||
|
# E241 - multiple spaces after ‘,’
|
||||||
|
# E501 - line too long
|
||||||
|
# W503 - line break before binary operator
|
||||||
|
ignore = E241,E501,W503
|
||||||
|
@ -49,9 +49,9 @@ class TestItemParsing:
|
|||||||
assert 'bar@baz' in items.files
|
assert 'bar@baz' in items.files
|
||||||
|
|
||||||
@pytest.mark.parametrize(('string', 'key', 'sep', 'value'), [
|
@pytest.mark.parametrize(('string', 'key', 'sep', 'value'), [
|
||||||
('path=c:\windows', 'path', '=', 'c:\windows'),
|
('path=c:\\windows', 'path', '=', 'c:\\windows'),
|
||||||
('path=c:\windows\\', 'path', '=', 'c:\windows\\'),
|
('path=c:\\windows\\', 'path', '=', 'c:\\windows\\'),
|
||||||
('path\==c:\windows', 'path=', '=', 'c:\windows'),
|
('path\\==c:\\windows', 'path=', '=', 'c:\\windows'),
|
||||||
])
|
])
|
||||||
def test_backslash_before_non_special_character_does_not_escape(
|
def test_backslash_before_non_special_character_does_not_escape(
|
||||||
self, string, key, sep, value):
|
self, string, key, sep, value):
|
||||||
|
@ -81,8 +81,8 @@ class TestSessionFlow(SessionTestBase):
|
|||||||
assert HTTP_OK in r4
|
assert HTTP_OK in r4
|
||||||
assert r4.json['headers']['Hello'] == 'World2'
|
assert r4.json['headers']['Hello'] == 'World2'
|
||||||
assert r4.json['headers']['Cookie'] == 'hello=world2'
|
assert r4.json['headers']['Cookie'] == 'hello=world2'
|
||||||
assert (r2.json['headers']['Authorization'] !=
|
assert (r2.json['headers']['Authorization']
|
||||||
r4.json['headers']['Authorization'])
|
!= r4.json['headers']['Authorization'])
|
||||||
|
|
||||||
def test_session_read_only(self, httpbin):
|
def test_session_read_only(self, httpbin):
|
||||||
self.start_session(httpbin)
|
self.start_session(httpbin)
|
||||||
@ -157,8 +157,8 @@ class TestSession(SessionTestBase):
|
|||||||
assert HTTP_OK in r2
|
assert HTTP_OK in r2
|
||||||
|
|
||||||
# FIXME: Authorization *sometimes* is not present on Python3
|
# FIXME: Authorization *sometimes* is not present on Python3
|
||||||
assert (r2.json['headers']['Authorization'] ==
|
assert (r2.json['headers']['Authorization']
|
||||||
HTTPBasicAuth.make_header(u'test', UNICODE))
|
== HTTPBasicAuth.make_header(u'test', UNICODE))
|
||||||
# httpbin doesn't interpret utf8 headers
|
# httpbin doesn't interpret utf8 headers
|
||||||
assert UNICODE in r2
|
assert UNICODE in r2
|
||||||
|
|
||||||
|
@ -119,8 +119,8 @@ class StrCLIResponse(str, BaseCLIResponse):
|
|||||||
elif self.strip().startswith('{'):
|
elif self.strip().startswith('{'):
|
||||||
# Looks like JSON body.
|
# Looks like JSON body.
|
||||||
self._json = json.loads(self)
|
self._json = json.loads(self)
|
||||||
elif (self.count('Content-Type:') == 1 and
|
elif (self.count('Content-Type:') == 1
|
||||||
'application/json' in self):
|
and 'application/json' in self):
|
||||||
# Looks like a whole JSON HTTP message,
|
# Looks like a whole JSON HTTP message,
|
||||||
# try to extract its body.
|
# try to extract its body.
|
||||||
try:
|
try:
|
||||||
|
11
tox.ini
11
tox.ini
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
|
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py27, py35, py36, pypy, codestyle
|
# pypy3 currently fails because of a Flask issue
|
||||||
|
envlist = py27, py37, pypy
|
||||||
|
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
@ -20,11 +21,3 @@ commands =
|
|||||||
--verbose \
|
--verbose \
|
||||||
--doctest-modules \
|
--doctest-modules \
|
||||||
{posargs:./httpie ./tests}
|
{posargs:./httpie ./tests}
|
||||||
|
|
||||||
[testenv:codestyle]
|
|
||||||
deps = pycodestyle
|
|
||||||
commands =
|
|
||||||
pycodestyle \
|
|
||||||
--ignore=E241,E501
|
|
||||||
# 241 - multiple spaces after ‘,’
|
|
||||||
# 501 - line too long
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user