mirror of
https://github.com/httpie/cli.git
synced 2025-02-13 13:18:45 +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/
|
||||
__pycache__/
|
||||
dist/
|
||||
httpie.egg-info/
|
||||
build/
|
||||
*.egg-info
|
||||
.cache/
|
||||
.tox
|
||||
.tox/
|
||||
.coverage
|
||||
*.pyc
|
||||
*.egg
|
||||
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
|
||||
|
||||
language: python
|
||||
os:
|
||||
- linux
|
||||
|
||||
env:
|
||||
global:
|
||||
- NEWEST_PYTHON=3.6
|
||||
|
||||
- NEWEST_PYTHON=3.7
|
||||
python:
|
||||
- 2.7
|
||||
- pypy
|
||||
- 3.4
|
||||
- 3.5
|
||||
- 3.6
|
||||
# Currently fails because of a Flask issue
|
||||
# - pypy3
|
||||
- 3.7
|
||||
- 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)
|
||||
|
||||
# Stock OSX Python
|
||||
# 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
|
||||
|
||||
# Latest Python 2.x from Homebrew
|
||||
- BREW_PYTHON_PACKAGE=
|
||||
- os: osx
|
||||
language: generic
|
||||
env:
|
||||
# Latest Python 2.7 from Homebrew
|
||||
- TOXENV=py27
|
||||
- BREW_INSTALL=python
|
||||
|
||||
# Latest Python 3.x from Homebrew
|
||||
- BREW_PYTHON_PACKAGE=python@2
|
||||
- os: osx
|
||||
language: generic
|
||||
env:
|
||||
- TOXENV=py36
|
||||
- BREW_INSTALL=python3
|
||||
|
||||
# Python Codestyle
|
||||
# Latest Python 3.x from Homebrew
|
||||
- TOXENV=py37 # <= needs to be kept up-to-date to reflect latest minor version
|
||||
- BREW_PYTHON_PACKAGE=python@3
|
||||
# Add a codestyle-only build
|
||||
- os: linux
|
||||
python: 3.6
|
||||
env: CODESTYLE=true
|
||||
|
||||
env: CODESTYLE_ONLY=true
|
||||
install:
|
||||
- |
|
||||
- |
|
||||
if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
|
||||
if [[ -n "$BREW_INSTALL" ]]; then
|
||||
brew update
|
||||
brew install "$BREW_INSTALL"
|
||||
fi
|
||||
sudo pip install tox
|
||||
sudo pip install tox
|
||||
if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then
|
||||
brew install "$BREW_PYTHON_PACKAGE"
|
||||
fi
|
||||
fi
|
||||
if [[ $CODESTYLE ]]; then
|
||||
pip install pycodestyle
|
||||
fi
|
||||
|
||||
script:
|
||||
- |
|
||||
- |
|
||||
if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
|
||||
if [[ $CODESTYLE ]]; then
|
||||
# 241 - multiple spaces after ‘,’
|
||||
# 501 - line too long
|
||||
pycodestyle --ignore=E241,E501
|
||||
else
|
||||
make
|
||||
fi
|
||||
if [[ $CODESTYLE_ONLY ]]; then
|
||||
make pycodestyle
|
||||
else
|
||||
make test
|
||||
fi
|
||||
else
|
||||
PATH="/usr/local/bin:$PATH" tox -e "$TOXENV"
|
||||
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
|
||||
|
@ -53,7 +53,8 @@ Go to https://github.com/jakubroztocil/httpie and fork the project repository.
|
||||
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
|
||||
@ -80,6 +81,9 @@ Running all tests:
|
||||
# Run all tests for code as well as packaging, etc.
|
||||
make test-all
|
||||
|
||||
# Test PEP8 compliance
|
||||
make pycodestyle
|
||||
|
||||
|
||||
Running specific tests:
|
||||
***********************
|
||||
@ -92,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.
|
||||
|
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
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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)'
|
||||
@ -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,
|
||||
))
|
||||
|
@ -254,8 +254,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(
|
||||
@ -338,10 +338,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
|
||||
|
||||
@ -426,8 +427,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
|
||||
@ -469,8 +470,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
|
||||
|
||||
@ -505,7 +506,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')
|
||||
|
@ -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:
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
@ -157,8 +157,8 @@ 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
|
||||
|
||||
|
@ -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:
|
||||
|
11
tox.ini
11
tox.ini
@ -3,7 +3,8 @@
|
||||
|
||||
|
||||
[tox]
|
||||
envlist = py27, py35, py36, pypy, codestyle
|
||||
# pypy3 currently fails because of a Flask issue
|
||||
envlist = py27, py37, pypy
|
||||
|
||||
|
||||
[testenv]
|
||||
@ -20,11 +21,3 @@ commands =
|
||||
--verbose \
|
||||
--doctest-modules \
|
||||
{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